UITableViewController和NSFetchedResultsController编辑问题

时间:2014-05-16 03:16:43

标签: ios core-data

在我的应用程序中,我使用CoreData作为后备存储管理音乐文件库。效果很好。我还使用NSFetchedResultsController将数据绑定到表视图以供显示,这也很好并且花花公子。当我尝试在表视图上启用编辑时出现问题。

像往常一样,我从YES返回tableView:canEditRowAtIndexPath:以允许编辑行,从而启用滑动以删除UI。这很好用,显示正确。但是,删除文件和诸如此类的东西之后,UITableView开始出现一些奇怪的渲染问题:

uitableview issues

我不向tableview发送任何消息以显式请求UI更新,因为获取的结果控制器通知我的UITableViewController子类,然后发送相应的消息:

/**
 * Handler for changing an entire section at once
 */
- (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:UITableViewRowAnimationRight];
            break;

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

/**
 * Handler for changing a single object, usually a row.
 */
- (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:UITableViewRowAnimationRight];
            break;

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

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

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:@[newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

/**
 * Called when the fetched results controller begins sending update messages.
 */
- (void) controllerWillChangeContent:(NSFetchedResultsController *) controller {
    [self.tableView beginUpdates];
}

/**
 * Called when the fetched results controller finishes sending updates.
 */
- (void) controllerDidChangeContent:(NSFetchedResultsController *) controller {
    [self.tableView endUpdates];
}

阅读完文档之后,我非常确定我需要做的就是从上下文中删除对象,如下所示:

- (void) tableView:(UITableView *) tableView commitEditingStyle:(UITableViewCellEditingStyle) editingStyle forRowAtIndexPath:(NSIndexPath *) indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {            
        // perform on the object context's background queue
        [[SQUPersistence sharedInstance].managedObjectContext performBlock:^{
            [[SQUPersistence sharedInstance].managedObjectContext deleteObject:[_fetchedResultsController objectAtIndexPath:indexPath]];

            // Save database
            [[SQUPersistence sharedInstance] save:nil];
        }];
    }
}

最终,UI进入如上所示的奇怪状态,并且该表与后备存储不同步,并且不执行动画。我这整个删除操作是错误的,还是我遇到了Apple的类错误?

1 个答案:

答案 0 :(得分:0)

我怀疑它是线程问题。如果您要在后台队列中删除,但是从主队列[_fetchedResultsController objectAtIndexPath:indexPath]引用该对象,我相信这会导致问题。

马上,我会通过尝试确认:

- (void) tableView:(UITableView *) tableView commitEditingStyle:(UITableViewCellEditingStyle) editingStyle forRowAtIndexPath:(NSIndexPath *) indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {  
        NSManagedObjectContext *context = _fetchedResultsController.managedObjectContext;          
        [context deleteObject:[_fetchedResultsController objectAtIndexPath:indexPath]];

        // Save database (You do not have to do this here)
        [context save:nil];
    }
}

如果你没有这样做的问题,我建议你离开它。在后台删除单个对象可能没什么好处。您可能会挂起的是保存操作,您实际上并不需要这样做。你可以离开保存直到用户退出或其他一点,任何延迟都会被UI更改掩盖。