Collection View 自动处理大量记录?
Collection View automatically handles large amounts of records?
我有一个变量保存来自 Core Data 的记录集合。有时它可以是数千条记录。如果我将这个变量输入到集合视图中,它会自动处理大量吗?
我希望集合从 Core Data 延迟加载到变量中,并且集合视图一次加载 10-20 个,只是为了处理视口。这好得令人难以置信,或者处理这个问题的最佳方法是什么?
如果当您在集合视图中时记录将发生变化并且您想要跟踪它,请使用获取的结果控制器。它们专为 table 视图而设计,但足够简单以适应集合视图。
否则,请为您的提取请求设置批量大小。这将确保一次仅从存储中获取一定数量的记录,如果未访问这些记录将返回故障。来自文档:
If you set a non-zero batch size, the collection of objects returned when the fetch is executed is broken into batches. When the fetch is executed, the entire request is evaluated and the identities of all matching objects recorded, but no more than batchSize objects’ data will be fetched from the persistent store at a time. The array returned from executing the request will be a proxy object that transparently faults batches on demand. (In database terms, this is an in-memory cursor.)
我使用 AshFurrow's 实现带有集合视图的获取结果控制器。
然后当你延迟加载你的 fetched results 控制器时,只需设置你的批量大小。
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Your added implementation
[fetchRequest setFetchBatchSize:20];
// More code...
aFetchedResultsController.delegate = self;
_fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
下面是 AshFurrow 的 NSFetchedResultsControllerDelegate 实现,我保留原样。然后在你的集合视图 delegate/dataSource 方法中使用你的 fetchedResultsController ,这与你在 table 视图中的方法非常相似。
// GitHub : AshFurrow FetchedResultsController + CollectionView
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// Begin updates
_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 {
// End updates
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 *fromIP = move[0];
NSIndexPath *toIP = move[1];
if ([deleteSections containsIndex:fromIP.section]) {
if (![insertSections containsIndex:toIP.section]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeInsert)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:toIP, nil];
_objectChanges[@(NSFetchedResultsChangeInsert)] = changeSet;
} else {
[changeSet addObject:toIP];
}
}
} else if ([insertSections containsIndex:toIP.section]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeDelete)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:fromIP, nil];
_objectChanges[@(NSFetchedResultsChangeDelete)] = changeSet;
} else {
[changeSet addObject:fromIP];
}
} 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:nil];
_objectChanges = nil;
_sectionChanges = nil;
}
我有一个变量保存来自 Core Data 的记录集合。有时它可以是数千条记录。如果我将这个变量输入到集合视图中,它会自动处理大量吗?
我希望集合从 Core Data 延迟加载到变量中,并且集合视图一次加载 10-20 个,只是为了处理视口。这好得令人难以置信,或者处理这个问题的最佳方法是什么?
如果当您在集合视图中时记录将发生变化并且您想要跟踪它,请使用获取的结果控制器。它们专为 table 视图而设计,但足够简单以适应集合视图。
否则,请为您的提取请求设置批量大小。这将确保一次仅从存储中获取一定数量的记录,如果未访问这些记录将返回故障。来自文档:
If you set a non-zero batch size, the collection of objects returned when the fetch is executed is broken into batches. When the fetch is executed, the entire request is evaluated and the identities of all matching objects recorded, but no more than batchSize objects’ data will be fetched from the persistent store at a time. The array returned from executing the request will be a proxy object that transparently faults batches on demand. (In database terms, this is an in-memory cursor.)
我使用 AshFurrow's 实现带有集合视图的获取结果控制器。 然后当你延迟加载你的 fetched results 控制器时,只需设置你的批量大小。
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Your added implementation
[fetchRequest setFetchBatchSize:20];
// More code...
aFetchedResultsController.delegate = self;
_fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
下面是 AshFurrow 的 NSFetchedResultsControllerDelegate 实现,我保留原样。然后在你的集合视图 delegate/dataSource 方法中使用你的 fetchedResultsController ,这与你在 table 视图中的方法非常相似。
// GitHub : AshFurrow FetchedResultsController + CollectionView
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// Begin updates
_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 {
// End updates
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 *fromIP = move[0];
NSIndexPath *toIP = move[1];
if ([deleteSections containsIndex:fromIP.section]) {
if (![insertSections containsIndex:toIP.section]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeInsert)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:toIP, nil];
_objectChanges[@(NSFetchedResultsChangeInsert)] = changeSet;
} else {
[changeSet addObject:toIP];
}
}
} else if ([insertSections containsIndex:toIP.section]) {
NSMutableArray *changeSet = _objectChanges[@(NSFetchedResultsChangeDelete)];
if (changeSet == nil) {
changeSet = [[NSMutableArray alloc] initWithObjects:fromIP, nil];
_objectChanges[@(NSFetchedResultsChangeDelete)] = changeSet;
} else {
[changeSet addObject:fromIP];
}
} 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:nil];
_objectChanges = nil;
_sectionChanges = nil;
}