FRC および TableView デリゲートで、矛盾しているように見える動作に遭遇しました。
- performFetchの最初の呼び出しにより、デリゲート メソッドが期待どおりに呼び出されます。ただし、FRC のbaseFetchの述語を更新してから再びperformFetchを呼び出すと、FRC デリゲート メソッドは呼び出されず、TableView は新しいデータで更新されません。テーブルを強制的に更新して新しいデータを表示するために、明示的にreloadDataを呼び出しています。
- performFetchの最初の呼び出しで、TableView のセクションが正しく構築されます。FRC を変更し (新しい FCR はfetchRequestとsectionNameKeyPathが異なります)、再びperformFetchを呼び出すと、予想どおり、テーブルとセクションが新しい結果に一致するように更新されます。ただし、元の FRC に戻ってperformFetchを呼び出すと、セクションの名前は正しくなりますが、以前の FRC のセクション/行構造のままです。セクションを強制的に更新するために、明示的にreloadSectionIndexTitlesを呼び出しています。
私の感じでは、何かが変更された場合、performFetchを呼び出すたびにデリゲートを起動する必要があります。reloadDataとreloadSectionIndexTitlesを明示的に呼び出すことは、デリゲートが存在する目的であるため、高価で不必要な手順のように思えます。何か不足していますか?
関連するコードは次のとおりです。
NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.myTable beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.myTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[self.myTable cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[self.myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[self.myTable reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.myTable insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.myTable deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.myTable endUpdates];
}
UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return [[currentFCR sections] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[currentFCR sections] objectAtIndex:section];
return section.name;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[currentFCR sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
取得中
- (NSFetchedResultsController *)FRC1 {
if (FRC1 != nil) {
return FRC1;
}
NSFetchRequest *request = [[DataProvider instance] getFetch];
[[DataProvider instance] sortListByFirstSort:request];
[request setFetchBatchSize:20];
FRC1 = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:[[DataProvider instance] managedObjectContext]
sectionNameKeyPath:@"groupName"
cacheName:nil];
return FRC1;
}
- (NSFetchedResultsController *)FRC2 {
if (FRC2 != nil) {
return FRC2;
}
NSFetchRequest *request = [[DataProvider instance] getFetch];
[[DataProvider instance] sortListBySecondSort:request];
[request setFetchBatchSize:20];
FRC2 = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:[[DataProvider instance] managedObjectContext]
sectionNameKeyPath:@"name"
cacheName:nil];
return FRC2;
}
-(void)doFetch{
NSError *error;
if (![currentFCR performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
[self.myTable reloadData];
[self.myTable reloadSectionIndexTitles];
}