Collection View 自动处理大量记录?

Posted

技术标签:

【中文标题】Collection View 自动处理大量记录?【英文标题】:Collection View automatically handles large amounts of records? 【发布时间】:2015-06-02 15:32:15 【问题描述】:

我有一个变量,其中包含来自 Core Data 的记录集合。有时可能是数千条记录。如果我将此变量输入到集合视图中,它会自动处理大量吗?

我希望集合是从 Core Data 延迟加载到变量中的,并且集合视图一次加载 10-20 个,只是为了处理视口。这真是太好了,还是最好的处理方法是什么?

【问题讨论】:

【参考方案1】:

我使用AshFurrow's 实现带有集合视图的获取结果控制器。 然后,当您延迟加载获取的结果控制器时,只需设置批量大小。

- (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 实现,我保留原样。然后在您的集合视图委托/数据源方法中使用您的 fetchedResultsController,这与您在表格视图中的使用方式非常相似。

// 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;

【讨论】:

【参考方案2】:

如果您在集合视图中时记录会发生变化并且您想要跟踪它,请使用获取的结果控制器。它们是为表格视图设计的,但足够简单以适应集合视图。

否则,请为您的提取请求设置批量大小。这将确保一次仅从存储中获取一定数量的记录,如果不访问它们将转回故障。来自文档:

如果您设置非零批量大小,则执行提取时返回的对象集合将分成多个批次。执行 fetch 时,会评估整个请求并记录所有匹配对象的身份,但一次从持久存储中获取不超过 batchSize 对象的数据。执行请求返回的数组将是一个代理对象,可以根据需要透明地对批次进行故障处理。 (在数据库术语中,这是一个内存游标。)

【讨论】:

以上是关于Collection View 自动处理大量记录?的主要内容,如果未能解决你的问题,请参考以下文章

您好,我正在使用 Collection View 单元格,我想记录其中有多少被单击“变为真”并返回下一个视图控制器

Redux记录:Store是如何自动调用reducers来处理action的

从 Collection View Xcode 中删除 Collection View Cell

ScrollTo indexPath 在 Collection View Cell 内的 Collection View (Nested CollectionView)

iOS开发之collection view 的视图裁剪问题

MVC学习笔记:入门