与performBatchUpdates崩溃的梦魇 [英] Nightmare with performBatchUpdates crash

查看:1935
本文介绍了与performBatchUpdates崩溃的梦魇的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在集合视图上的performBatchUpdates期间面临崩溃的噩梦。

I am facing a nightmare of a crash during performBatchUpdates on a collection view.

问题基本上是这样的:我在一个目录上有很多图像服务器。我想在集合视图中显示这些文件的缩略图。但必须以异步方式从服务器下载缩略图。当他们到达时,他们将使用以下内容插入集合视图:

The problem is basically this: I have a lot of images on a directory on a server. I want to show the thumbnails of those files on a collection view. But the thumbnail have to be downloaded from the server asynchronously. As they arrive they will be inserted on the collection view using something like this:

dispatch_async(dispatch_get_main_queue(),
             ^{
               [self.collectionView performBatchUpdates:^{

                 if (removedIndexes && [removedIndexes count] > 0) {
                   [self.collectionView deleteItemsAtIndexPaths:removedIndexes];
                 }

                 if (changedIndexes && [changedIndexes count] > 0) {
                   [self.collectionView reloadItemsAtIndexPaths:changedIndexes];
                 }

                 if (insertedIndexes && [insertedIndexes count] > 0) {
                   [self.collectionView insertItemsAtIndexPaths:insertedIndexes];
                 }

               } completion:nil];
             });

问题是这个(我想)。假设在time = 0时,集合视图有10个项目。然后我再向服务器添加100个文件。应用程序查看新文件并开始下载缩略图。随着缩略图下载,它们将被插入到集合视图中。但是因为下载可能需要不同的时间并且这个下载操作是异步的,所以有一次iOS会忘记该集合有多少元素,并且整个事情会因这个灾难性的臭名昭着的消息而崩溃。

the problem is this (I think). Suppose that at time = 0, the collection view has 10 items. I then add 100 more files to the server. The application sees the new files and start downloading the thumbnails. As the thumbnails download they will be inserted on the collection view. But because the downloads can take different times and this download operation is asynchronous, at one point iOS will lost track of how many elements the collection has and the whole thing will crash with this catastrophic infamous message.


***由于未捕获的异常'NSInternalInconsistencyException'终止应用程序,原因:'无效更新:无效
第0部分中的项目数。包含的项目数更新后的
现有部分(213)必须等于更新前该部分中包含的
项目数(154),加上或减去
插入或删除的项目数从该部分(插入40
,删除0)并加上或减去移入
或该部分之外的项目数量(0移入,0移出)。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (213) must be equal to the number of items contained in that section before the update (154), plus or minus the number of items inserted or deleted from that section (40 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'

我有一些可疑的证明是,如果我打印数据集上的项目数,我看到的确是213.所以,d ataset匹配正确的号码,消息是无意义的。

The proof I have something fishy is going on is that if I print the count of items on the data set I see exactly 213. So, the dataset matches the correct number and the message is nonsense.

之前我遇到过这个问题,这里,但这是一个iOS 7项目。不知怎的,现在iOS 8上的问题又回来了,解决方案就没有了,现在数据集 IS IN SYNC

I have had this problem before, here but that was an iOS 7 project. Somehow the problem returned now on iOS 8 and the solutions there are not working and now the dataset IS IN SYNC.

推荐答案

我认为问题是由索引引起的。

I think the problem is caused by the indexes.

密钥:


  • 对于更新和删除的项目,索引必须是原始项目的索引。

  • 对于插入的项目,索引必须是最终项目的索引。

这是一个带注释的演示代码:

Here is a demo code with comments:

class CollectionViewController: UICollectionViewController {

    var items: [String]!

    let before = ["To Be Deleted 1", "To Be Updated 1", "To Be Updated 2", "To Be Deleted 2", "Stay"]
    let after = ["Updated 1", "Updated 2", "Added 1", "Stay", "Added 2"]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Refresh", style: .Plain, target: self, action: #selector(CollectionViewController.onRefresh(_:)))

        items = before
    }

    func onRefresh(_: AnyObject) {

        items = after

        collectionView?.performBatchUpdates({
            self.collectionView?.deleteItemsAtIndexPaths([NSIndexPath(forRow: 0, inSection: 0), NSIndexPath(forRow: 3, inSection: 0), ])

            // Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete and reload the same index path
            // self.collectionView?.reloadItemsAtIndexPaths([NSIndexPath(forRow: 0, inSection: 0), NSIndexPath(forRow: 1, inSection: 0), ])

            // NOTE: Have to be the indexes of original list
            self.collectionView?.reloadItemsAtIndexPaths([NSIndexPath(forRow: 1, inSection: 0), NSIndexPath(forRow: 2, inSection: 0), ])

            // Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert item 4 into section 0, but there are only 4 items in section 0 after the update'
            // self.collectionView?.insertItemsAtIndexPaths([NSIndexPath(forRow: 4, inSection: 0), NSIndexPath(forRow: 5, inSection: 0), ])

            // NOTE: Have to be index of final list
            self.collectionView?.insertItemsAtIndexPaths([NSIndexPath(forRow: 2, inSection: 0), NSIndexPath(forRow: 4, inSection: 0), ])

        }, completion: nil)
    }

    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath)

        let label = cell.viewWithTag(100) as! UILabel

        label.text = items[indexPath.row]

        return cell
    }
}

这篇关于与performBatchUpdates崩溃的梦魇的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆