UICollectionView使用performBatchUpdates执行更新

dar*_*sky 31 xcode objective-c ipad ios uicollectionview

我有一个UICollectionView我试图动态/动画插入项目.所以我有一些函数可以异步下载图像,并希望批量插入项目.

获得数据后,我想执行以下操作:

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

现在代替了***,我应该传递一个数组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];
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 30

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

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

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

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

因此,在您的情况下,您必须先将图像添加到集合视图数据源,然后再调用insertItemsAtIndexPaths.然后,集合视图将要求数据源委托函数提供插入项的视图.

  • `UICollectionView是绝对荒谬的.我所拥有的是一个带有数据源数组的集合视图,我使用GCD在线下载数据,并在主线程中更新UI.而已!集合视图甚至无法更改其内容大小以允许自动滚动到项目.你能把你的全班发布到某个地方,所以我可以看一下吗?我一直在与收集视图争夺3天,而Apple声称它们是新的表格视图.我真的在拉我的头发我的截止日期非常接近. (7认同)

Plo*_*lot 11

我刚刚用Swift实现了它.所以我想分享我的实施.首先初始化NSBlockOperations数组:

    var blockOperations: [NSBlockOperation] = []
Run Code Online (Sandbox Code Playgroud)

在控制器中将更改,重新初始化数组:

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    blockOperations.removeAll(keepCapacity: false)
}
Run Code Online (Sandbox Code Playgroud)

在做了改变对象的方法:

    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!])
                }
            })
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

在更改部分方法中:

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))
                }
            })
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在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)
    })
}
Run Code Online (Sandbox Code Playgroud)

我个人也在deinit方法中添加了一些代码,以便在ViewController即将解除分配时取消操作:

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

    blockOperations.removeAll(keepCapacity: false)
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*Nik 5

我在从索引中删除项目时遇到了类似的问题,这是我认为在使用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];
        }];
Run Code Online (Sandbox Code Playgroud)

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

  • 插入或删除后不需要重新加载集合视图.但是你的解决方案运作良好. (4认同)
  • 此代码将删除崩溃,但您之后将重新加载整个表.你也可以只调用[self.collectionView reloadData]; ....它不会给你删除效果. (3认同)