我在我的应用程序中使用核心数据,它将存储下载的数据。当app下载数据时,我会将它们保存在privateQueueContext(NSPrivateQueueConcurrencyType)
核心数据保存完成后,我应该更新UI。为了实现这一点,我已经定义了NSFetchedResultsController委托方法。正如我所料,当核心数据发生变化时,会调用这些委托方法。
在didChangeObject
方法中我插入新单元格,但当核心数据中插入了许多对象并发出以下错误消息时,它会导致崩溃
***断言失败 - [UICollectionView _endItemAnimations] CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。更新无效:第0部分中的项目数无效。更新后现有部分中包含的项目数(379)必须等于更新前该部分中包含的项目数(325),加上或减去数字从该部分插入或删除的项目(插入52个,删除0个)以及加入或减去移入或移出该部分的项目数量(0移入,0移出)。 with userInfo(null)
我在完成新的单元格插入动画之前假设数据源更改。
我希望很多人会遇到同样的问题,堆栈溢出中有很多类似的问题,但答案对我来说都没有。你能帮助我吗?
在核心数据中插入新对象
for (NSDictionary *obj in books){
Book *book = [Book insertInManagedObjectContext:context];
book.udid = [obj objectForKey:@“id”]
}
[context performBlock:^{
NSError *error = nil;
if ([context save:&error]) {
NSLog(@“success”);
}
}];
获取结果控制器委托
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
self.blockOperation = [NSBlockOperation new];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
__weak UICollectionView *collectionView = self.collectionView;
switch(type) {
case NSFetchedResultsChangeInsert:{
[self.blockOperation addExecutionBlock:^{
[collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:newIndexPath.item + 1 inSection:newIndexPath.section]]];
}];
break;
}
default:
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.collectionView performBatchUpdates:^{
[self.blockOperation start];
} completion:nil];
}
答案 0 :(得分:0)
您的performBlock
保存时间过长。你可以
只需保存主线程即可。应该花费一瞬间来保存500本书,并且由于UI中没有任何重要的事情发生(用户在等待),因此无需在一个块中执行此操作。
使用performBlockAndWait
代替。只有在保存完成后才会更新表视图。用户的结果与保存主线程非常相似。
在没有阻止操作的情况下使用NSFetchedResultsControllerDelegate
。遵循Xcode提供的获取结果控制器模板。这可能比仅保存主线程更慢,因为UI将获得多次更新。