UICollectionView在performBatchUpdates上锁定主线程约10秒

Nic*_*ing 2 objective-c nsfetchedresultscontroller uicollectionview uicollectionviewlayout

我有一个300个单元格的集合视图,由NSFetchedResultsController驱动.每隔一段时间,所有对象都会更新,所以我收到委托消息告诉我,并让集合视图处理更新,就像我查看tableview一样.不幸的是,每次发生这种情况时它会锁定主线程几秒钟......我不知道为什么.这是我的代码:

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{

    [self.cascadeViewController.collectionView performBatchUpdates:^{

    NSLog(@"performingBatchUpdates");

    for (NSDictionary *change in self.changes) {

        [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

            NSFetchedResultsChangeType type = [key unsignedIntegerValue];

            if (type == NSFetchedResultsChangeInsert) {

                [self.cascadeViewController.collectionView insertItemsAtIndexPaths:@[obj]];

            } else if (type == NSFetchedResultsChangeDelete) {

                [self.cascadeViewController.collectionView deleteItemsAtIndexPaths:@[obj]];

            } else if (type == NSFetchedResultsChangeUpdate) {

                [self.cascadeViewController.collectionView reloadItemsAtIndexPaths:@[obj]];

            } else if (type == NSFetchedResultsChangeMove) {

                [self.cascadeViewController.collectionView moveItemAtIndexPath:obj[0] toIndexPath:obj[1]];

            }

        }];
    }

    NSLog(@"performingBatchUpdates end");

} completion:^(BOOL finished) {

    NSLog(@"completion");

    // TODO: implement
    //    [self configureMessageAndFooterView];

}];

NSLog(@"end of method");

[self.changes removeAllObjects];

}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?一次更新的所有300个对象不会在我的应用程序的实际执行中不断发生,但足以让我担心它.我正在使用股票UICollectionViewFlowLayout - 我需要做一些更自定义的事情吗?

小智 5

performBatchUpdates:completion:在大约100个元素的集合视图中锁定主线程几秒钟也有同样的问题.

在花费太多时间在这个问题上我找到了一个解决方案:确保单元格的大小(-collectionView:layout:sizeForItemAtIndexPath:通过itemSize布局属性返回或定义)没有小数值.我通过应用floor计算出的细胞高度解决了我的性能问题.

话虽如此,我不知道为什么会这样.通过观察我们的异形运行的堆栈跟踪,大量的时间都花在了-[UIViewCollectionViewUpdate _computeGaps],这反过来调用-[NSArray sortedArrayUsingSelector:]数百甚至数千倍(以及CFSortIndexes,__CFSimpleMergeSort...).通过仅使用整数值作为单元格的高度,sortedArrayUsingSelector调用次数少于10次,整个过程在几分之一秒内完成.