NSFetchedResultsController에서 내용을 수신하는 UICollectionView가 있습니다. 데이터는 여러 API- 엔드 포인트에서 제공됩니다 (서버 설계가 내 손안에 있음). 첫 번째 호출은 메타 데이터를 전달하며 각 엔트리 (> 10.000)보다 관련 데이터를 가져 오기위한 API 호출이 있어야합니다.CoreData 업데이트 중에 NSFetchedResultsController를 UICollectionView로 바꾸는 중 오류가 발생했습니다.
CollectionView 여러 속성에 대해 필터링 할 수 있으며, 각 필터는 사용자가 필터링을 변경 때, 나는 새와 현재의 FRC를 교체해야하는 다른 sectionNameKeyPath
이 필요합니다. CoreData이
*** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UICollectionView.m:4422
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete item 9 from section 0 which only contains 1 items before the update'
으로 다음 응용 프로그램 충돌을 업데이트 때 그래서 충돌을 피할 수있는 방법은 무엇입니까?
편집 : NSFetchedResultsControllerDelegate에 대한 추가 코드 :
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
_objectChanges = [NSMutableDictionary dictionary];
_sectionChanges = [NSMutableDictionary dictionary];
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
if (type == NSFetchedResultsChangeInsert || type == NSFetchedResultsChangeDelete) {
NSMutableIndexSet *changeSet = _sectionChanges[@(type)];
if (changeSet != nil) {
[changeSet addIndex:sectionIndex];
} else {
_sectionChanges[@(type)] = [[NSMutableIndexSet alloc] initWithIndex:sectionIndex];
}
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
NSMutableArray *changeSet = _objectChanges[@(type)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] init];
_objectChanges[@(type)] = changeSet;
}
switch(type) {
case NSFetchedResultsChangeInsert:
[changeSet addObject:newIndexPath];
break;
case NSFetchedResultsChangeDelete:
[changeSet addObject:indexPath];
break;
case NSFetchedResultsChangeUpdate:
[changeSet addObject:indexPath];
break;
case NSFetchedResultsChangeMove:
[changeSet addObject:@[indexPath, newIndexPath]];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSMutableArray *moves = _objectChanges[@(NSFetchedResultsChangeMove)];
if ([moves count] > 0) {
NSMutableArray *updatedMoves = [[NSMutableArray alloc] initWithCapacity:[moves count]];
NSMutableIndexSet *insertSections = _sectionChanges[@(NSFetchedResultsChangeInsert)];
NSMutableIndexSet *deleteSections = _sectionChanges[@(NSFetchedResultsChangeDelete)];
for (NSArray *move in moves) {
NSIndexPath *oldIndexPath = move[0];
NSIndexPath *newIndexPath = move[1];
if ([deleteSections containsIndex:[oldIndexPath section]]) {
if (![insertSections containsIndex:[newIndexPath section]]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeInsert)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:newIndexPath, nil];
_objectChanges[@(NSFetchedResultsChangeInsert)] = changeSet;
} else {
[changeSet addObject:newIndexPath];
}
}
} else if ([insertSections containsIndex:[newIndexPath section]]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeDelete)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:oldIndexPath, nil];
_objectChanges[@(NSFetchedResultsChangeDelete)] = changeSet;
} else {
[changeSet addObject:oldIndexPath];
}
} else {
[updatedMoves addObject:move];
}
}
if ([updatedMoves count] > 0) {
_objectChanges[@(NSFetchedResultsChangeMove)] = updatedMoves;
} else {
[_objectChanges removeObjectForKey:@(NSFetchedResultsChangeMove)];
}
}
NSMutableArray *deletes = _objectChanges[@(NSFetchedResultsChangeDelete)];
if ([deletes count] > 0) {
NSMutableIndexSet *deletedSections = _sectionChanges[@(NSFetchedResultsChangeDelete)];
[deletes filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSIndexPath *evaluatedObject, NSDictionary *bindings) {
return ![deletedSections containsIndex:evaluatedObject.section];
}]];
}
NSMutableArray *inserts = _objectChanges[@(NSFetchedResultsChangeInsert)];
if ([inserts count] > 0) {
NSMutableIndexSet *insertedSections = _sectionChanges[@(NSFetchedResultsChangeInsert)];
[inserts filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSIndexPath *evaluatedObject, NSDictionary *bindings) {
return ![insertedSections containsIndex:evaluatedObject.section];
}]];
}
UICollectionView *collectionView = self.collectionView;
[collectionView performBatchUpdates:^{
NSIndexSet *deletedSections = _sectionChanges[@(NSFetchedResultsChangeDelete)];
if ([deletedSections count] > 0) {
[collectionView deleteSections:deletedSections];
}
NSIndexSet *insertedSections = _sectionChanges[@(NSFetchedResultsChangeInsert)];
if ([insertedSections count] > 0) {
[collectionView insertSections:insertedSections];
}
NSArray *deletedItems = _objectChanges[@(NSFetchedResultsChangeDelete)];
if ([deletedItems count] > 0) {
[collectionView deleteItemsAtIndexPaths:deletedItems];
}
NSArray *insertedItems = _objectChanges[@(NSFetchedResultsChangeInsert)];
if ([insertedItems count] > 0) {
[collectionView insertItemsAtIndexPaths:insertedItems];
}
NSArray *reloadItems = _objectChanges[@(NSFetchedResultsChangeUpdate)];
if ([reloadItems count] > 0) {
[collectionView reloadItemsAtIndexPaths:reloadItems];
}
NSArray *moveItems = _objectChanges[@(NSFetchedResultsChangeMove)];
for (NSArray *paths in moveItems) {
[collectionView moveItemAtIndexPath:paths[0] toIndexPath:paths[1]];
}
} completion:^(BOOL finished) {
[[self refreshControl] endRefreshing];
}];
_objectChanges = nil;
_sectionChanges = nil;
}
위임 콜백은 어떻게 처리합니까? 다시로드하거나 개별 변경 사항에 애니메이션을 적용하려고합니까? – Wain
나는 모두 시도했습니다 performBatchUpdates를 사용합니다 : controllerDidChangeContent에서 그리고 블록에서 나는 itemChanges 및 sectionChanges에 대한 두 개의 mutableDictionaries를 처리합니다. 그러나 테스트를 위해 나는 또한 controllerDidChangeContent에서 간단한 "reloadData"를 시도했습니다. – MatzeLoCal
은 변경 처리 코드와 변경 사항을 핵심 데이터로 저장하는 방법을 보여줍니다. – Wain