多个 nsfetchedresultscontroller 或一个

multiple nsfetchedresultscontrollers or a single one

我正在使用核心数据,我有一个 UI具有动态部分数的 TableView。

我有一个名为日期的实体 - 它有一个标题和指向另一个实体的关系 - 该实体的 ID 是将要显示的部分数据。

哪种方法最好,为什么?

一个。有一个 NSFetchedResultControllers 数组 - 在每个部分中,我使用谓词过滤数据。然后我只是把数据呈现给每个部分。

乙。我有一个 NSFetchedResultController 并获取所有数据 - 然后在我的 CellForRow 中检查是否应该显示它们。

摄氏度。我删除了关系,并在我的实体中添加了一个名为 sectionId 的额外属性,并使用 A 或 B。

就 UI 性能而言,最佳方法是什么?

编辑:

示例 - 我有

实体 1:数据

Data Id : 0, Title : First, (Relationship) section : 0
Data Id : 1, Title : Second, (Relationship) section : 0
Data Id : 2, Title : FisrtB, (Relationship) section : 1

条目 2:SectionsName

SectionId : 0 , Name : TitleA , etc (to-many- relationhsip to Data)
SectionId : 1 , Name : TitleB , etc (to-many- relationhsip to Data)

所以,问题实际上是:

看起来虽然您只需要实体 2 (sectionID) 的一个属性,但您仍然需要关系才能获取该实体并最终获取该属性 (sectionID)。因此我建议选项B。FRC越少越好。你在这里只需要一个。在您的 CellForRow 中,您将通过使用 indexPath 在获取的结果数组中获取当前实体。拥有当前实体后,您现在可以访问实体 2,它是第一个实体的 属性。拥有实体 2 后,您现在拥有所需的属性,即实体 2 的部分 ID。您现在可以在 table 视图中显示该属性(部分 ID)。

已编辑以反映对原始问题的更改

您几乎肯定应该使用原始问题中的选项 B(后续编辑中的选项 A):单个 NSFetchedResultsController,基于 Data 实体,但具有 table 视图部分由 section 关系确定。

您的抓取结果控制器可以完成将对象分成正确部分的所有艰苦工作:确保 FRC 底层的抓取首先按 section.sectionId(或 section.name 排序,如果您更喜欢),并将 FRC 的 sectionNameKeyPath 指定为 section.sectionId(或 section.name)。样板 FRC/tableView 代码会自动将对象放入正确的部分。

上述样板代码:

#pragma mark - TableView Datasource delegate

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

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> sectionInfo  = self.fetchedResultsController.sections[section];
    return [sectionInfo numberOfObjects];
}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    Data *data = [self.fetchedResultsController objectAtIndexPath:indexPath];
    ....
    return cell;
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
    return sectionInfo.name;
}

#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Data" inManagedObjectContext:self.context];
    [fetchRequest setEntity:entity];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sectionSort = [[NSSortDescriptor alloc] initWithKey:@"section.sectionId" ascending:YES];
    // Add any other sort criteria
    ....
    NSArray *sortDescriptors = @[sectionSort, ...];
    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:@"section.sectionId" cacheName:nil];
    self.fetchedResultsController = aFetchedResultsController;
    aFetchedResultsController.delegate = self;
    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    
    return _fetchedResultsController;
}

#pragma mark - FRC delegate methods

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
       atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        default:
            break;
     }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeMove:
            [tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView endUpdates];
}

几乎可以肯定只使用一个获取结果控制器更好。 (在这一点上我同意@Lee,但我不明白他为什么推荐选项 B,其中包括 更多 FRC。)

总结您的数据模型:

Section <------->> Date

您可以简单地获取该部分并调整 datasource 方法:

// number of sections
return self.fetchedResultsController.fetchedObjects.count;

// number of rows in section
Section *section = [self.fetchedResultsController objectAtIndexPath:
  [NSIndexPath indexPathForRow:section inSection:0]];
return section.dates.count;

// cellForRowAtIndexPath
/* create a convenience function in the Section class to return a
   sorted array from the NSSet "dates". */
Section *section = [self.fetchedResultsController objectAtIndexPath:
  [NSIndexPath indexPathForRow:indexPath.section inSection:0]];
Date *date = section.sortedDates[indexPath.row];
/* configure the cell based on the date object */

所以,A是更好的选择。