UICollectionView使用performBatchUpdates执行更新
-
11-12-2019 - |
题
我有一个 UICollectionView
我试图动态/用动画插入项目。所以我有一些异步下载图像的功能,并希望批量插入项目。
一旦我有我的数据,我想做以下事情:
[self.collectionView performBatchUpdates:^{
for (UIImage *image in images) {
[self.collectionView insertItemsAtIndexPaths:****]
}
} completion:nil];
现在代替了 ***
, ,我应该传递一个数组 NSIndexPaths
, ,其应指向要插入的新项的位置。我很困惑,因为在提供位置后,如何提供应该在该位置显示的实际图像?
谢谢!
更新资料:
resultsSize
包含数据源数组的大小, self.results
, ,在从数据中添加新数据之前 newImages
.
[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的集合视图编程指南":
要插入、删除或移动单个部分或项目,您必须遵循 这些步骤:
- 更新数据源对象中的数据。
- 调用集合视图的适当方法以插入或删除节或项。
在通知 任何更改的集合视图。集合视图方法假定 您的数据源包含当前正确的数据。如果是的话 不是,集合视图可能会收到错误的项目集 您的数据源或要求不存在的项目并使您的 应用程序。
因此,在您的情况下,您必须先将图像添加到集合视图数据源,然后调用 insertItemsAtIndexPaths
.然后,集合视图将询问数据源委托函数以提供插入项的视图。
其他提示
我刚刚用Swift实现了这一点。所以我想分享我的实现。首先初始化一个NSBlockOperations数组:
var blockOperations: [NSBlockOperation] = []
在控制器将改变,重新初始化数组:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
blockOperations.removeAll(keepCapacity: false)
}
在did change对象方法中:
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!])
}
})
)
}
}
在did更改部分方法中:
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))
}
})
)
}
}
最后,在did控制器中确实改变了内容方法:
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];
}];
这有助于我删除所有崩溃和断言失败。