iOS CoreData NSFetchedResultsController sections and sorting

I currently have a CoreData entity that has a name and date attributes, and I would like to create a NSFetchedResultsController that returns the results sectioned by name sorted by date descending (both the sections and its contents), and if possible, only one entry per section. I prefer not to use NSDictionaryResultType .

Lets say I have the following entries:

Name | Date (year/month/day)
-----+----------------------
Anne | 2014/01/16
John | 2014/01/17
John | 2014/01/15
Nick | 2014/01/13
Nick | 2014/01/10

For the above data I wish to obtain only the following results:

Section | Entry Date
--------+-----------
John    | 2014/01/17
Anne    | 2014/01/16
Nick    | 2014/01/13

How do I create the NSFetchedResultsController to obtain only the data and in the order listed above?


As of now I have the following code:

NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:moc];
[fetchRequest setEntity:entity];

NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"my predicate" argumentArray:...]];
[fetchRequest setPredicate:predicate];

NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:moc
                                          sectionNameKeyPath:@"name"
                                                   cacheName:nil];

The above code sections the data by name , but each section doesn't have its entries sorted by date AND it has entries that are not from that name !

The result that I want is the table showing unique name sorted by date like showed in the beginning of the post.

Update: I've been unable to do this, so I switched to result type dictionary and used group by for now, I will leave the question open in the hopes someone knows how to do it.


There is no way (that I am aware of) to limit each section to one result in the NSFetchedResultsController.

But, you might not have to do this. You could probably get away with not displaying everything that is not in the first section.

Also, you should be aware that you should not section the request by using any other key than the key used in the primary sort descriptor


If you are using this with a tableView you could try something like this:

FRC creation

NSSortDescriptor *sdName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSSortDescriptor *sdDate = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
// sort by name, then sort by date
[fetchRequest setSortDescriptors:@[sdName, sdDate]];
[fetchRequest setFetchBatchSize:20];

NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                    managedObjectContext:moc
                                      sectionNameKeyPath:@"name"
                                               cacheName:nil];

// fetch...

and the tableViewDataSource:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSFetchedResultsController *fetchedResultsController = [self fetchedResultsController];
    return [fetchedResultsController.sections count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1; // only display one result for each section
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    NSFetchedResultsController *fetchedResultsController = [self fetchedResultsController];
    YourObject *object = [fetchedResultsController objectAtIndexPath:indexPath];
    ... configure cell ...

Depending on how many objects you have per person this might not be feasible. If there are a lot of entries you won't display I would recommend to normalize the core data model. Eg:

在这里输入图像描述

You then would display a list of Persons. But maybe this normalization would be a good idea regardless of the number of objects per name. Fetching more objects than are displayed smells fishy to me.


关于我的评论,这是一些代码片段

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"EntityThingO"];

NSSortDescriptor *sortDescriptorDate = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
NSSortDescriptor *sortDescriptorName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortDescriptorDate , sortDescriptorName];
[fetchRequest setFetchBatchSize:10];

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                managedObjectContext:context
                                                                  sectionNameKeyPath:@"date"
                                                                           cacheName:nil];
链接地址: http://www.djcxy.com/p/6144.html

上一篇: NSFetchedResultsController部分按类别排序

下一篇: iOS CoreData NSFetchedResultsController部分和排序