I have the following data model:
After opening a document, I would like to list the layers (as sections) with the underlying objects in a UITableView
.
I have implemented the fetched results controller the following way:
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create the fetch request for the entity
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"DB_Layer"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size
[fetchRequest setFetchBatchSize:10];
// Sort by stacking order, descending
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"stackingOrder" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create the fetched results controller, and set this controller to be the delegate
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:@"Layer"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
// Fetch the results into the fetched results controller
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return fetchedResultsController;
}
The problem is that this gives me the list of all layers (even those belonging to other documents).
I believe I should use an NSPredicate
to narrow down the results, but I am not sure how.
What I would need to have is:
- a list organized into sections by
DB_Layer
objects (I am not sure where I can specify what to group the results by) - each section containing the objects/groups of the corresponding layer.
EDIT:
Based on Richard Casey's answer, I can now get the list of layers, but it requires me to retrieve al开发者_如何转开发l DB_Shape
objects (even those belonging to other documents), and filter them with predicates.
This is a big performance hit.
What I am really looking for is a way to do it the other way around:
- pass the current document to the
NSFetchedResultsController
, - retrieve the related objects, creating a section for each
DB_Layer
object, - list the corresponding -- either grouped (
DB_Group
) or separate (DB_Shape
) objects within the section.
What I am really looking for is a way to do it the other way around:
- pass the current document to the NSFetchedResultsController,
- retrieve the related objects, creating a section for each DB_Layer object,
- list the corresponding -- either grouped (DB_Group) or separate (DB_Shape) objects within the section.
A NSFetchResultsController
can only return one kind of entity. So you cannot list both DB_Group
and DB_Shape
entities with the current model. The DB_Group
entity shares all attributes with DB_Shape
so you could make DB_Shape
a subentity of DB_Group
.
This way DB_Layer
only has a one-to-many for DB_Group
relation, that just so happen to include the shapes as well. You fetch request will then:
- Fetch
DB_Group
entities. - Grouped by the
DB_Layer
. - Filtered by a predicate based on the layers
DB_Document
.
For presentation you use isKindOfClass:
if you need different view types for groups and shapes.
You are correct. To list layers for a particular document, you can use an NSPredicate.
The following code (added before you create your NSFetchedResultsController) should do it.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"document.name == %@",docName];
[fetchRequest setPredicate:predicate];
The docName variable in the above code is the name attribute of the document you want to list.
When you create the NSFetchedResultsController, the sectionKeyNamePath parameter specifies the attribute that is used for generating groups for your tableview. If you want to list the objects/groups by the corresponding layer, you would probably want to have the NSFetchRequest run against the DB_Shape entity and then use @"layer.name" for the sectionKeyNamePath.
Hope this helps!
Not exactly the answer to your question but if you have a specific DB_Document
object in hand, then you don't have to fetch you just ask the object for the contents of it's layer
relationship and then go from there.
That's rather the whole point of having relationships. You already know what objects you need and you don't have filter the entire persistent store looking form them.
Not sure what the structure for your DB_Layer object looks like, but what you can do is modify the NSFetchedResultsController initialization as follows to specify the field within DB_layer you want to create a section on. For example, if you have a field called "field1" in your core data object that you want to section your results on, updating the sectionNameKeyPath should create sections for you:
// Create the fetched results controller, and set this controller to be the delegate
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
**sectionNameKeyPath:@"field1"** cacheName:@"Layer"];
Using a predicate will filter your results - not sure that is what you are after. The above snippet should group your results into sections based on "field1".
精彩评论