为什么我的PHFetchResultChangeDetails已经改变了索引,当我所做的只是插入到最后?

xap*_*hod 10 objective-c photos ios ios8

我正在使用Photos框架编写iOS8应用程序.我真的很喜欢PHFetchResultChangeDetails.但有一些我不明白的事情:当我使用以下代码将新照片保存到相机胶卷时,我会回来插入和更改.我希望只插入.

使它具体化:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

PHAssetChangeRequest* newPhotoChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest* albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:_album];
[albumChangeRequest addAssets:[NSArray arrayWithObject:newPhotoChangeRequest.placeholderForCreatedAsset]];
...
Run Code Online (Sandbox Code Playgroud)

操作是使用上面的代码插入3张照片.之前:ipad上的5张照片.之后:ipad中的8张照片.PHFetResultChangeDetails处理程序上的断点显示:

(lldb) po insertionIndexPaths
<__NSArrayM 0x7913be10>(
<NSIndexPath: 0x78e39020> {length = 2, path = 0 - 5},
<NSIndexPath: 0x78e3c910> {length = 2, path = 0 - 6},
<NSIndexPath: 0x78e39480> {length = 2, path = 0 - 7}
)
Run Code Online (Sandbox Code Playgroud)

- >好:有道理!这些是我刚插入的照片(最后3个索引路径).

(lldb) po changeIndexPaths
<__NSArrayM 0x78e3c420>(
<NSIndexPath: 0x78e3c7e0> {length = 2, path = 0 - 2},
<NSIndexPath: 0x78e3c7a0> {length = 2, path = 0 - 3},
<NSIndexPath: 0x78e3c7b0> {length = 2, path = 0 - 4}
)
Run Code Online (Sandbox Code Playgroud)

- >不要理解:为什么这些被认为是"改变了"?这些是相机胶卷上的现有照片......我没有对它们做任何事情.

谢谢你的帮助.

更新:看起来它可能与选择有关.我忽略了提到,当已经选择了一些细胞时会发生这种情况.我所看到的是,当在collectionView的末尾插入新项目时,一些选定的单元格被随机取消选择 - 我认为那些具有changeIndexPaths.哇,太糟糕了 - 我看不出我的代码是如何做到的!任何提示?

UPDATE2:所以,看起来虚假的changeIndexPaths总是直接在插入路径之前的3个indexPaths(总是在结尾处).为什么?!

UPDATE3:我还看到UICollectionView的performBatchUpdates崩溃,如果数据源事先是正确的,如果有插入和重新加载的话.例如,当更改看起来像这样:

<PHFetchResultChangeDetails: 0x1742b91a0> 
before=<PHFetchResult: 0x1702b5d20> count=31, 
after=<PHFetchResult: 0x1702b5ea0> count=33, 
hasIncremental=1 deleted=(null), 
inserted=<NSMutableIndexSet: 0x17444aef0>[number of indexes: 2 (in 2 ranges), indexes: (30 32)], 
changed=<NSMutableIndexSet: 0x17444a9b0>[number of indexes: 4 (in 2 ranges), indexes: (27-29 31)], 
hasMoves=0
Run Code Online (Sandbox Code Playgroud)

...然后我的应用程序在performBatchUpdates崩溃,但有异常:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete item 31 from section 0 which only contains 31 items before the update'
Run Code Online (Sandbox Code Playgroud)

这是performBatchUpdates的代码,我直接从Apple文档(!)复制,因此我认为没有理由为changeIndexPaths包含索引31,因为在插入之前,count = 31:

 [self.collectionView performBatchUpdates:^{

      if( deletionIndexPaths.count )
                [self.collectionView deleteItemsAtIndexPaths:deletionIndexPaths];
      if( insertionIndexPaths.count )
                [self.collectionView insertItemsAtIndexPaths:insertionIndexPaths];
      if( changeIndexPaths.count )
                [self.collectionView reloadItemsAtIndexPaths:changeIndexPaths];
      if( moveBlock )
                moveBlock(self.collectionView);
 } ...
Run Code Online (Sandbox Code Playgroud)

小智 5

回复:更新 3

不管示例代码怎么说,changedIndexes 不能像这样在 performBatchUpdates 中使用。

该指数PHFetchResultChangeDetails.changedIndexes是相对于原来的取结果在removedIndexes指标被删除,之后在insertedIndexes新的索引添加。

但是 UITableView 和 UICollectionView API 要求 reloadItems* 方法在批量更新中调用时具有任何其他更改之前的索引。

要解决此问题,请重新加载并在批量更新之外移动条目,例如:

    [self.collectionView performBatchUpdates:^{

        if( deletionIndexPaths.count )
            [self.collectionView deleteItemsAtIndexPaths:deletionIndexPaths];
        if( insertionIndexPaths.count )
            [self.collectionView insertItemsAtIndexPaths:insertionIndexPaths];
    } ... ]
    if( changeIndexPaths.count )
        [self.collectionView reloadItemsAtIndexPaths:changeIndexPaths];
    if( moveBlock )
        moveBlock(self.collectionView);
Run Code Online (Sandbox Code Playgroud)