【发布时间】:2010-07-29 16:23:05
【问题描述】:
首先,抱歉问题太长了。
我知道这里很少有讨论类似问题的问题,但这些都没有讨论 NSFetchedResultsController 与委托以及单独线程中的更新。没有一个解决方案对我有帮助。
这些是现有的问题:
- NSFetchedResultsController: using of NSManagedObjectContext during update brings to crash
- Determining which core Data attribute/property change triggered a NSFetchedResultsController update
- Core Data executeFetchRequest throws NSGenericException (Collection was mutated while being enumerated)
- Collection was mutated while being enumerated. How to determine which set?
- 等
现在谈谈我的问题:
- 我有一个单独的线程来更新来自网络的核心数据对象(使用套接字)。
- 很少有视图控制器显示来自同一核心数据对象的数据(每个选项卡都包含一个显示其过滤数据的视图控制器)。
- 每个视图控制器都有自己的
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];
}
在表视图数据源方法中,我直接使用托管对象。
【问题讨论】:
标签: iphone multithreading core-data delegates nsfetchedresultscontroller