首先,很抱歉问题太长了。
我知道这里很少有问题可以讨论类似的问题,但是这些都没有讨论 NSFetchedResultsController 与委托以及单独线程中的更新。没有一个解决方案对我有帮助。
这些是现有的问题:
- NSFetchedResultsController:在更新期间使用 NSManagedObjectContext 会导致崩溃
- 确定哪个核心数据属性/属性更改触发了 NSFetchedResultsController 更新
- 核心数据 executeFetchRequest 抛出 NSGenericException(枚举时集合发生了变异)
- 枚举时集合发生了突变。如何确定是哪一组?
- 等等
现在关于我的问题:
- 我有一个单独的线程来更新来自网络的核心数据对象(使用套接字)。
- 很少有视图控制器显示来自同一核心数据对象的数据(每个选项卡都包含一个显示其过滤数据的视图控制器)。
- 每个视图控制器都有自己的实例,
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];
}
在表视图数据源方法中,我直接使用托管对象。