4

当我的 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;
        }
    }
}

这完美地工作,问题是当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 个新行并且计数保持在 1 而不是变成 2。

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

4

2 回答 2

12

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

在您的情况下,当插入第一个对象时,insertRowsAtIndexPaths在新对象的 FRC 委托方法中调用,但不是显示额外的行,而是将“空”单元格替换为不同的单元格,因此行数仍然是一。

如果您 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 按如下方式修改 FRC 委托方法,它应该可以工作:

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;
于 2013-07-20T13:00:12.617 回答
1

PSA:如果您还没有检查过Yang Meyer的在空表上显示单元格的解决方案,我建议您这样做。这是处理空表或空 NSFetchedResultsController 的一种聪明且简单得多的方法。

Yang Meyer 处理空表视图的最佳实践

我使用它的方式是在我的 中viewDidLoad,我最初会假设结果是空的。只有当我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;
    }
}

简单,但非常有效。

于 2014-12-01T22:04:31.537 回答