在NSFetchedResultsController的空表上定制单元格

我试图放置一个自定义的空单元格,当我的UITableView是空的。

我使用下面的代码:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { return 1; } return count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell * cell = nil; int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { // return empty cell cell = [self getEmptyCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } else { cell = [self getMyQuestionCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } return cell; } 

FRC didChangeObject实现:

 - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } } 

这工作完美,problam是当fetchedObject.count> 0比我得到以下错误:

 CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to - controllerDidChangeContent: Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null) 

我知道这是因为我插入了一个新的行,计数停留在1而不是2。

我如何解决它以适应我的行为?

在更新表视图后, numberOfRowsInSection返回的值必须与之前的行数加上插入的行数减去删除的行数完全匹配。

在你的情况下,插入第一个对象时, insertRowsAtIndexPaths在FRC委托方法中为新对象调用,而不是显示一个额外的行,“空”单元被replace为一个不同的单元格,所以行数是还是一个。

它应该工作,如果您修改FRC委托方法controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:如下所示:

 case NSFetchedResultsChangeInsert: if ([[self.fetchedResultsController fetchedObjects] count] == 1) { // First object inserted, "empty cell" is replaced by "object cell" [tableView reloadRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; } else { [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; } break; case NSFetchedResultsChangeDelete: if ([[self.fetchedResultsController fetchedObjects] count] == 0) { // Last object removed, "object cell" is replaced by "empty cell" [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else { [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } break; 

PSA:如果您还没有检查出Yang Meyer的解决scheme,但是在空桌上展示细胞,我build议您这样做。 处理空表或者清空NSFetchedResultsController是很聪明和简单的方法。

杨梅尔处理空表视图的最佳实践

我用它的方式是,我会在我的viewDidLoad ,我最初假设结果是空的。 只有当我的fetchedResultsController有对象时,我fetchedResultsController更改数据源。

FJFetchedDataController.h

 @interface FJFetchedDataTableController : UITableViewController <NSFetchedResultsControllerDelegate, UITableViewDelegate> @end 

FJFetchedDataController.m

 @implementation FJFetchedDataTableController { @private FJEmptyDataSource *_emptyDataSource; }; - (void)viewDidLoad { [super viewDidLoad]; // create the empty data source _emptyDataSource = [[FJEmptyDataSource alloc] init]; // point the tableView to the empty data source self.tableView.dataSource = _emptyDataSource; self.fetchedResultsController.delegate = self; // TODO: configure your fetchedResultsController here NSError *error; if (![self.fetchedResultsController performFetch:&error]) { // TODO: error handling } if ([self.fetchedResultsController.fetchedObjects count]) { // set the table source back to itself (or whatever you want as the data source) // since we know we have results self.tableView.dataSource = self; return; } } 

简单,但真正有效。