首先,很抱歉问题太长了。
我知道这里有一些讨论类似问题的问题,但没有一个讨论NSFetchedResultsController与委托一起使用以及在单独的线程中进行更新。而且没有任何解决方案能帮助我。
这些是现有的问题:
- NSFetchedResultsController:在更新期间使用NSManagedObjectContext会导致崩溃
- 确定哪个Core Data属性/属性更改触发了NSFetchedResultsController更新
- Core Data executeFetchRequest引发NSGenericException(集合在枚举时被突变)
- 在枚举时突变了集合。如何确定哪个集?
- 等等。
- 我有一个单独的线程,通过套接字从Web更新核心数据对象。
- 有几个视图控制器显示来自相同核心数据对象的数据(每个选项卡包含一个显示其过滤数据的视图控制器)。
- 每个视图控制器都有自己的
NSFetchedResultsController
实例,并将委托设置为self。
有时候在单独的线程中更新数据时会收到was mutated while being enumerated
异常,有时会导致应用程序崩溃。
我已经进行了许多代码操作,以尝试修复它,似乎没有什么帮助。
我尝试不使用直接从表格视图数据源方法中管理对象。相反,我创建了一个包含字典列表的数组。我在上面的didChangeObject
方法中填充这些字典。这样,在视图控制器中根本不触摸托管对象。
然后我明白了问题在于NSFetchedResultsController,它可能一直迭代数据。这就是与单独线程中的数据更新发生冲突的对象。
问题是,一旦我有了一个带有委托的NSFetchedResultsController(意味着它“监视”数据并始终更新委托),我如何在单独的线程中更新核心数据对象。NSFetchedResultsControllerDelegate实现:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if ( self.tabBarController.selectedIndex == 0 ) {
UITableView *tableView = self.tableView;
@try {
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
@catch (NSException * e) {
NSLog(@"Exception in didChangeObject: %@", e);
}
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
if ( self.tabBarController.selectedIndex == 0 ) {
@try {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
@catch (NSException * e) {
NSLog(@"Exception in didChangeSection: %@", e);
}
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
在表视图的数据源方法中,我直接使用托管对象。