ios UICollectionView 使用 performBatchUpdates 执行更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12656648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UICollectionView Performing Updates using performBatchUpdates
提问by darksky
I have a UICollectionView
which I am trying to insert items into it dynamically/with animation. So I have some function that downloads images asynchronously and would like to insert the items in batches.
我有一个UICollectionView
我正在尝试动态/使用动画将项目插入其中。所以我有一些异步下载图像的功能,并希望批量插入项目。
Once I have my data, I would like to do the following:
获得数据后,我想执行以下操作:
[self.collectionView performBatchUpdates:^{
for (UIImage *image in images) {
[self.collectionView insertItemsAtIndexPaths:****]
}
} completion:nil];
Now in place of the ***
, I should be passing an array of NSIndexPaths
, which should point to the location of the new items to be inserted. I am very confused since after providing the location, how do I provide the actual image that should be displayed at that position?
现在代替***
,我应该传递一个 的数组NSIndexPaths
,它应该指向要插入的新项目的位置。我很困惑,因为在提供了位置之后,如何提供应该在该位置显示的实际图像?
Thank you
谢谢
UPDATE:
更新:
resultsSize
contains the size of the data source array, self.results
, before new data is added from the data at newImages
.
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];
回答by Martin R
See Inserting, Deleting, and Moving Sections and Itemsfrom the "Collection View Programming Guide for iOS":
请参阅“ iOS 集合视图编程指南”中的插入、删除和移动部分和项目:
To insert, delete, or move a single section or item, you must follow these steps:
- Update the data in your data source object.
- Call the appropriate method of the collection view to insert or delete the section or item.
It is critical that you update your data source before notifying the collection view of any changes. The collection view methods assume that your data source contains the currently correct data. If it does not, the collection view might receive the wrong set of items from your data source or ask for items that are not there and crash your app.
要插入、删除或移动单个部分或项目,您必须执行以下步骤:
- 更新数据源对象中的数据。
- 调用集合视图的适当方法来插入或删除部分或项目。
在通知集合视图任何更改之前更新数据源至关重要。集合视图方法假定您的数据源包含当前正确的数据。如果没有,集合视图可能会从您的数据源接收错误的项目集,或者请求不存在的项目并导致您的应用程序崩溃。
So in your case, you must add an image to the collection view data source first and then call insertItemsAtIndexPaths
. The collection view will then ask the data source delegate function to provide the view for the inserted item.
因此,在您的情况下,您必须先将图像添加到集合视图数据源,然后调用insertItemsAtIndexPaths
. 然后集合视图将要求数据源委托函数为插入的项目提供视图。
回答by Plot
I just implemented that with Swift. So I would like to share my implementation. First initialise an array of NSBlockOperations:
我刚刚用 Swift 实现了它。所以我想分享我的实现。首先初始化一个 NSBlockOperations 数组:
var blockOperations: [NSBlockOperation] = []
In controller will change, re-init the array:
在控制器会改变,重新初始化数组:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
blockOperations.removeAll(keepCapacity: false)
}
In the did change object method:
在 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!])
}
})
)
}
}
In the did change section method:
在 did change 部分方法中:
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))
}
})
)
}
}
And finally, in the did controller did change content method:
最后,在 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)
})
}
I personally added some code in the deinit method as well, in order to cancel the operations when the ViewController is about to get deallocated:
我个人也在 deinit 方法中添加了一些代码,以便在 ViewController 即将被释放时取消操作:
deinit {
// Cancel all block operations when VC deallocates
for operation: NSBlockOperation in blockOperations {
operation.cancel()
}
blockOperations.removeAll(keepCapacity: false)
}
回答by Nik
I was facing the similar issue while deleting the item from index and this is what i think we need to do while using performBatchUpdates:
method.
我在从索引中删除项目时遇到了类似的问题,这就是我认为我们在使用performBatchUpdates:
方法时需要做的。
1# first call deleteItemAtIndexPath to delete the item from collection view.
1#首先调用deleteItemAtIndexPath从集合视图中删除项目。
2# Delete the element from array.
2#从数组中删除元素。
3# Update collection view by reloading data.
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];
}];
This help me to remove all the crash and assertion failures.
这有助于我消除所有崩溃和断言失败。