在我的应用程序中,我使用CoreData作为后备存储管理音乐文件库。效果很好。我还使用NSFetchedResultsController
将数据绑定到表视图以供显示,这也很好并且花花公子。当我尝试在表视图上启用编辑时出现问题。
像往常一样,我从YES
返回tableView:canEditRowAtIndexPath:
以允许编辑行,从而启用滑动以删除UI。这很好用,显示正确。但是,删除文件和诸如此类的东西之后,UITableView
开始出现一些奇怪的渲染问题:
我不向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的类错误?
答案 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更改掩盖。