ios - son - ¿Por qué mi PHFetchResultChangeDetails ha cambiado Índices, cuando todo lo que hice fue insertar al final?
seo h3 (1)
Estoy escribiendo una aplicación iOS8 usando el marco de Photos. Realmente me encanta PHFetchResultChangeDetails. Pero hay algo que no entiendo: cuando guardo nuevas fotos en el rollo de la cámara usando el siguiente código, recupero las inserciones Y los cambios. Espero solo inserciones.
Para hacerlo concreto:
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest* newPhotoChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest* albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:_album];
[albumChangeRequest addAssets:[NSArray arrayWithObject:newPhotoChangeRequest.placeholderForCreatedAsset]];
...
La operación es insertar 3 fotos usando el código anterior. Antes: 5 fotos en ipad. Después: 8 fotos en el ipad. El punto de interrupción en el controlador PHFetResultChangeDetails muestra:
(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}
)
-> BUENO: ¡tiene sentido! estas son las fotos que acabo de insertar (los últimos 3 indexpaths).
(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}
)
-> NO ENTIENDES: ¿por qué se consideran "cambiados"? Estas son las fotos existentes en el rollo de la cámara ... No les hice nada.
Gracias por tu ayuda.
ACTUALIZACIÓN: parece que podría tener algo que ver con la selección. Olvidé mencionar que esto sucede cuando ya hay algunas celdas seleccionadas. Lo que estoy viendo es que cuando se insertan nuevos elementos al final de collectionView, algunas de las celdas seleccionadas se deseleccionan al azar, creo que las que tienen changeIndexPaths. Wow, eso apesta - ¡No puedo ver cómo mi código puede estar haciendo eso! ¿Algún consejo?
UPDATE2: por lo tanto, parece que los espurios changeIndexPaths son siempre los 3 indexPaths directamente antes de las rutas de inserción (que siempre están al final). ¡¿Por qué?!
ACTUALIZACIÓN3: También veo bloqueos en performBatchUpdates de UICollectionView, cuando el origen de datos está actualizado correctamente de antemano, si hay insertos y recargas. Por ejemplo, cuando el cambio se ve así:
<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
... entonces mi aplicación se bloquea en performBatchUpdates con excepción:
*** Terminating app due to uncaught exception ''NSInternalInconsistencyException'', reason: ''attempt to delete item 31 from section 0 which only contains 31 items before the update''
Aquí está el código de performBatchUpdates, que copié directamente de la documentación de Apple (!), Así que no veo ninguna razón por la cual changeIndexPaths contenga el índice 31, dado que antes de las inserciones, el recuento = 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);
} ...
Re: Actualización 3
A pesar de lo que dice el código de ejemplo, changedIndexes no se puede usar en performBatchUpdates como este.
Los índices PHFetchResultChangeDetails.changedIndexes son relativos al resultado de recuperación original después de que se eliminan los índices en removedIndexes, y después de que se agregan los índices nuevos en insertedIndexes.
Sin embargo, las API UITableView y UICollectionView requieren que los métodos reloadItems *, cuando se llaman en una actualización por lotes, tengan índices antes de cualquier otro cambio.
Para solucionar esta llamada, vuelva a cargar y mueva las entradas fuera de las actualizaciones por lotes, por ejemplo:
[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);