多个 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)
所以,问题实际上是:
- 一个。有一个 returns 所有数据(总共 3 个)的 FRC,然后我应该
找到他们去的正确部分?
- 乙。或者每个部分都有一个 FRC - first FRC returns the top2
我可以通过
indexPath.row
访问的数据,第二个相同
FRC.
看起来虽然您只需要实体 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
是更好的选择。
我正在使用核心数据,我有一个 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)
所以,问题实际上是:
- 一个。有一个 returns 所有数据(总共 3 个)的 FRC,然后我应该 找到他们去的正确部分?
- 乙。或者每个部分都有一个 FRC - first FRC returns the top2
我可以通过
indexPath.row
访问的数据,第二个相同 FRC.
看起来虽然您只需要实体 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
是更好的选择。