UICollectionView使用performBatchUpdates执行更新

我有一个UICollectionView ,我试图dynamic插入项目/animation。 所以我有一些function,asynchronous下载图像,并希望批量插入项目。

一旦我有我的数据,我想要做以下几点:

 [self.collectionView performBatchUpdates:^{ for (UIImage *image in images) { [self.collectionView insertItemsAtIndexPaths:****] } } completion:nil]; 

现在代替*** ,我应该传递一个NSIndexPaths数组,它应该指向要插入的新项目的位置。 自提供位置后,我非常困惑,我该如何提供应该在该位置显示的实际图像?

谢谢


更新:

resultsSize中的数据添加新数据之前, resultsSize包含数据源数组的大小self.results

 [self.collectionView performBatchUpdates:^{ int resultsSize = [self.results count]; [self.results addObjectsFromArray:newImages]; NSMutableArray *arrayWithIndexPaths = [NSMutableArray array]; for (int i = resultsSize; i < resultsSize + newImages.count; i++) [arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; [self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths]; } completion:nil]; 

请参阅“适用于iOS的集合视图编程指南 ”中的插入,删除和移动节和项目 :

要插入,删除或移动单个部分或项目,您必须执行以下步骤:

  1. 更新数据源对象中的数据。
  2. 调用收集视图的相应方法来插入或删除节或项目。

在通知任何更改的集合视图之前,更新数据源至关重要。 集合视图方法假定您的数据源包含当前正确的数据。 如果没有,收集视图可能会从您的数据源收到错误的项目集合,或者询问那些不存在的项目,并使您的应用程序崩溃。

所以在你的情况下,你必须首先添加一个图像集合视图数据源,然后调用insertItemsAtIndexPaths 。 然后,集合视图将要求数据源委托函数为插入的项目提供视图。

我只是用Swift来实现它。 所以我想分享我的实施。 首先初始化一个NSBlockOperations数组:

  var blockOperations: [NSBlockOperation] = [] 

在控制器中会改变,重新初始化数组:

 func controllerWillChangeContent(controller: NSFetchedResultsController) { blockOperations.removeAll(keepCapacity: false) } 

在做了改变对象的方法:

  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { if type == NSFetchedResultsChangeType.Insert { println("Insert Object: \(newIndexPath)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.insertItemsAtIndexPaths([newIndexPath!]) } }) ) } else if type == NSFetchedResultsChangeType.Update { println("Update Object: \(indexPath)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.reloadItemsAtIndexPaths([indexPath!]) } }) ) } else if type == NSFetchedResultsChangeType.Move { println("Move Object: \(indexPath)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!) } }) ) } else if type == NSFetchedResultsChangeType.Delete { println("Delete Object: \(indexPath)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.deleteItemsAtIndexPaths([indexPath!]) } }) ) } } 

在改变部分的方法:

 func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { if type == NSFetchedResultsChangeType.Insert { println("Insert Section: \(sectionIndex)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.insertSections(NSIndexSet(index: sectionIndex)) } }) ) } else if type == NSFetchedResultsChangeType.Update { println("Update Section: \(sectionIndex)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.reloadSections(NSIndexSet(index: sectionIndex)) } }) ) } else if type == NSFetchedResultsChangeType.Delete { println("Delete Section: \(sectionIndex)") blockOperations.append( NSBlockOperation(block: { [weak self] in if let this = self { this.collectionView!.deleteSections(NSIndexSet(index: sectionIndex)) } }) ) } } 

最后,在控制器确实改变了内容的方法:

 func controllerDidChangeContent(controller: NSFetchedResultsController) { collectionView!.performBatchUpdates({ () -> Void in for operation: NSBlockOperation in self.blockOperations { operation.start() } }, completion: { (finished) -> Void in self.blockOperations.removeAll(keepCapacity: false) }) } 

我亲自在deinit方法中添加了一些代码,以便在ViewController即将取消分配时取消操作:

 deinit { // Cancel all block operations when VC deallocates for operation: NSBlockOperation in blockOperations { operation.cancel() } blockOperations.removeAll(keepCapacity: false) } 

我从索引中删除项目时遇到了类似的问题,这是我认为在使用performBatchUpdates:方法时需要做的事情。

1#先调用deleteItemAtIndexPath从集合视图中删除项目。

2#从数组中删除元素。

3#通过重新加载数据更新集合视图。

 [self.collectionView performBatchUpdates:^{ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag inSection:0]; [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]]; [self.addNewDocumentArray removeObjectAtIndex:sender.tag]; } completion:^(BOOL finished) { [self.collectionView reloadData]; }]; 

这有助于我删除所有崩溃和断言失败。