原文地址
Core Data是很好的东西,开发人员不用关心数据存储细节和SQL语句即可进行数据持久化,但Core Data使用不合理的话也将给自己产生不少坑,本人自认也是Core Data小白一枚,只是想给大家分享一个个人结合NSFetchedResultsController作为UICollectionView数据源开发过程碰到的问题。
场景如下:
//懒加载 NSFetchedResultsController getter
- (NSFetchedResultsController *)recordsFetchedResultsController
{
if (_recordsFetchedResultsController == nil)
{
NSManagedObjectContext *moc = [NSManagedObjectContext MR_defaultContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([xxx class])
inManagedObjectContext:moc];
NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"xxx" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects: sd1, nil];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setIncludesPendingChanges:YES];
_recordsFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:nil
cacheName:nil];
[_recordsFetchedResultsController setDelegate:self];
NSError *error = nil;
if (![_recordsFetchedResultsController performFetch:&error])
{
DDLogError(@"Error performing fetch: %@", error);
}
}
return _recordsFetchedResultsController;
}
//数据源
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.recordsFetchedResultsController sections][section];
return [sectionInfo numberOfObjects];
}
//NSFetchedResultsController delegate
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
dispatch_async(dispatch_get_main_queue(), ^{
if (controller == self.recordsFetchedResultsController)
{
switch (type)
{
case NSFetchedResultsChangeInsert:
[_recordsCollectionView insertItemsAtIndexPaths:@[newIndexPath]];
break;
case NSFetchedResultsChangeDelete:
[_recordsCollectionView deleteItemsAtIndexPaths:@[indexPath]];
break;
case NSFetchedResultsChangeMove:
[_recordsCollectionView deleteItemsAtIndexPaths:@[indexPath]];
[_recordsCollectionView insertItemsAtIndexPaths:@[newIndexPath]];
break;
case NSFetchedResultsChangeUpdate:
[_recordsCollectionView reloadItemsAtIndexPaths:@[indexPath]];
break;
default:
break;
}
}
});
}
以上是未优化前的代码,时常在进行Items
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath...
进行增删改后出现App崩溃,原因如下:
NSInternalInconsistencyException
Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (4) must be equal to the number of items contained in that section before the update (4), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).
原因显而易见,正如描述的那样,在cell 的增删时没有对
```的数量进行更新,导致cell的数量与数据源的数量不一致而程序崩溃。
  在网上找了很久都没找着解决办法,后来上GitHub找了个NSFetchedResultsController 与 UICollectionView搭配使用的范例(在这表示感谢作者分享),仔细看了一下作者的使用方式,发现更为规范整洁,于是对自己现有的代码进行优化,bug就解决了。
[NSFetchedResultsController与UICollectionView结合使用范例](https://github.com/Christian1313/CollectionViewWithSectionsAndNSFetchresultController/blob/master/CollectionViewWithNSFetchResultControllerAndSections/DataCollectionViewController.m)