Although there is sample code in the ADC for parent/child (one to many rather than inheritance) core data, the child relationship is managed by simply loading all of the related objects into a set, and then into an array. The application I have in mind may have huge amounts of related data per parent object, therefore I would like to use NSFetchedResultsController on the child side. My attempts to do this have worked other than the controllerDidChangeContent delegate callback. With one fetched results controller on the master tableviewcontroller and another on the many side, and aFetchedResultsController.delegate = self; the delegate callbacks were fired against random objects - errors returned from invalid selector 'controllerDidChangeContent:' on things like the toolbar and sqllite whenever the underlying data was updated.
Can anyone suggest working sample code of how to use NSFetchedResultsController in both parent and child parts of a relationship.
You definitely can implement an app with several table views in which each table view has a table view controller as its datasource/delegate and each table view controller has its own fetched results controller (that may fetch objects of different entities and/or with different filter predicates and/or with different sort descriptor(s)).
It would be hard to give you specific recommendations without knowing more about what your are doing (with code examples) and the specific issue(s) that you are having.
Related
Currently I have a UITableView with its data source being an NSFetchedResultsController. The most important thing the NSFetchedResultsController does is automatically update my table if there are any changes, via delegate methods. However, I no longer need to do a fetch to get my entity, call it "Pictures" for now. I have another entity called Folder, and folders have a relationship with Pictures, so every folder has an NSSet pictures.
So instead of fetching all pictures that belong to a certain folder, now I can just do folder.pictures, and that returns what I need, and I can assign that to an array and set that as my tableView source. However, this doesn't give me automatic table updates like an NSFetchedResultsController would.
My question is how can I have the functionality of an NSFetchedResultsController (that is, the delegate methods that automatically update my table) without executing a fetch? I don't need to fetch anymore since I have an NSSet with the desired NSManagedObjects.
What's wrong with the fetched results controller? Just keep it and use the dot notation for relationship sets as well - you get the best of both worlds.
The real advantage of the fetched results controller is actually hidden. It will fetch your objects (folders) alright - but maybe it will not fetch all the relationship attributes (pictures). This is called faulting. It means that core data will get the data in the background if it is needed. It is automatically optimized for speed and good memory usage. For example, the potentially huge array of your datasource will not have to be all in memory at once, something that is unavoidable with an array.
Thus, you really do not want to get rid of the FRC. She is your friend. Stay faithful to her. ;-)
My iPhone app has a summary page (UITableView) where I would like to show a quick overview and therefore I need to get info from several entities. It was suggested to create an abstract parent entity and have my two entities as children of this one. This do allow me to fetch the two entities using the one fetchedresultscontroller.
This works but I find that I need to filter the return a small bit. Because of the 'hack' above these entities have nothing in common so I need completely separate predicates.so from EntityA I would need "color = blue" and from EntityB "length >= 10". Because the entity I'm actually querying have none of these this doesn't work at all.
Is there a way to do this or what's the best approach here?
Niether the UITableView or the NSFetchedResultsController is designed to deal with more than one entity at a time. Moreover, it seldom makes any sense to try to do so. If you find yourself in such a situation, you probably need to rethink your data model design.
If entities are logically associated with each other then they should be linked by a relationship. If data from any two objects is to be displayed in the same tableviewCell without being gibberish then they must have some logical association and therefore should be linked by a relationship of some kind. To display in the table, you fetch one side of the relationship and then walk the relationship/s to find the other related objects.
If the logical association is strong, it should be defined as a formal relationship in the data model e.g.:
EntityA{
//... some attributes
b<-->B.a
}
EntityB{
//...some attributes
a<-->A.b
}
However, if the relationship is weak or transient, then you should use a fetched property to relate them. The fetched property dynamically searches for other entities based on a preprogrammed fetch.
EntityA{
creationDate:date
someBs--(creationDate=$FETCH_SOURCE.creationDate)-->B
}
EntityB{
creationDate:date
}
A key concept here is that Core Data is providing the entire model layer of your Model-View-Controller design. It is not just a dumb database but an active object graph that models both the data itself and its behavior. Once you have a properly designed data model, problems with the controllers and views resolve themselves automatically.
If i understand correctly, you can use notifications and send a dictionary of required information to the UITableView view controller class.
I have three entities with one-to-many relationships (Book <--->> Page <--->> Text)
I want to use one table view to present Book.titles, one table view for Page.no and one view to show the Text when clicking on a Page.no.
Do I need to setup up a fetchedResultsController for each entity or can I get access to a Text object
using the Book entity - Book.pages... etc?
If I understand your question correctly, you only need one fetched results controller and CoreData will do the rest.
So, you fill an NSFetchedResultsController with all the books you want to display and present them with a UITableViewController subclass. Then when the user selects one, you pass this book on to another UITableViewController subclass which uses book.pages to get and display all the pages in that book. This idea is then repeated to show the text entities.
HTH
PS - If you aren't already, you may find it useful to use xCode's Managed Object Class generator to ensure book.pages and pages.texts are correctly set up. To use this, open your .xcdatamodel file, highlight an entity and choose File->New File and choose Managed Object Class and then follow the steps.
You can access all objects via the relationships but depending on how complex your tableviews are, it may get tricky to manage the datasource methods. It's doable though!
For instance, if you decide to fetch the books, provided you have a reference to the instance you get all pages and put them in an Array with:
Book *bookItem = [self.frc objectAtIndexPath:indexPath];
NSArray *dataSource = [[book objectForKey:#"pages"] allObjets];
Another option is to create an abstract class and make it a parent of all 3 entities, then fetch using this class which will give you an array of all books, pages and text. From there you can test for the class and populate the tables accordingly.
I have an entity with a number of to-many relationships. I present certain properties of the entity in a tableview, using a NSFetchedResultsController. Of all the relationships the entity has, the values of only 1 of the relationships are displayed (they are currently faulted in the cellforrowat... method). It seems to me that this could have a performance impact. Is it possible to fault a specific relationship at the time of creating the Fetch request, so that CoreData does not have to fetch the values when the table is being scrolled?
I'm not sure that I understand the data model you're describing. If you are only displaying members of one of your entity's to-many relationships as the content for the table's rows, then you can fetch only the properties on display in each of the visible rows using -setPropertiesToFetch: on your fetch request, like in the following example:
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:#"title", #"thumbnailImage", nil];
[fetchRequest setPropertiesToFetch:propertiesToFetch];
[propertiesToFetch release];
However, if what you're describing is a list of entities, with one of the displayed elements in the table row being from a to-one relationship, you can use -setRelationshipKeyPathsForPrefetching: like Barry suggests. However, in that case I'd suggest denormalizing your data model and moving that property from being within a relationship to being directly within the original entity. Traversing relationships is much more expensive than accessing properties.
First, I would not assume that the default Core Data behavior is less performant than your proposed approach: without data to back up your efforts, optimization is almost certainly going to go awry.
That said, I believe -[NSFetchRequest setRelationshipKeyPathsForPrefetching:] will accomplish what you want.
You could manually fault in objects, but I don't think you'll gain anything. Whether you fault in all the objects at once, or you fault them in one at a time as needed, each object is still going to be faulted in individually.
I have written apps that do exactly what you describe, fault in a large amount of data to display in a table view, and have never noticed a performance penalty. Remember, only the objects that correspond to table view cells that will be displayed will be faulted in.
In general, I'd say don't try to outsmart Core Data. It's got years of performance optimizations in it at this point. While, intuitively, it may seem like faulting in 100 objects would require 100 database queries, this is not necessarily the case.
This seems like a typical problem, but I have a UITableView that has identical behavior for two separate data sources. What is the best way of going about designing the class hierarchy to have as little duplication and if/else conditions? The view controller is going to do the same exact thing to both data sources, they're just unique in their data set. Should I have the parent controller just set its data source/respective title?
The same issue is relevant as well when using a UISegmentControl for displaying two views with the same interfaces, but different data sources.
Be careful with your terminology here. A UITableView has something called a dataSource but you seem to be referring, essentially, to two different sets of data.
In the case you're suggesting, in the table's dataSource (the object that adheres to the UITableViewDataSource protocol), I'd have three arrays.
currentlyViewedArray
datasetOneArray
datasetTwoArray
In the dataSource methods, use the currentlyViewedArray as the source of the table's data.
Then, set the currentlyViewedArray to whichever array you want to view:
self.currentlyViewedArray = self.datasetOneArray;
[theTableView reloadData];
You can use the UISegmentedControl to switch between the two arrays.