CollectionViewController.m line 439
__50-[CollectionViewController photoLibraryDidChange:]_block_invoke
致命异常:NSInternalInconsistencyException
尝试删除并重新加载相同的索引路径({length = 2,path = 0 – 26007})
- - (void)photoLibraryDidChange:(PHChange *)changeInstance
- {
- // Call might come on any background queue. Re-dispatch to the main queue to handle it.
- dispatch_async(dispatch_get_main_queue(),^{
- // check if there are changes to the assets (insertions,deletions,updates)
- PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResults];
- if (collectionChanges) {
- // get the new fetch result
- self.assetsFetchResults = [collectionChanges fetchResultAfterChanges];
- UICollectionView *collectionView = self.collectionView;
- if (![collectionChanges hasIncrementalChanges] || [collectionChanges hasMoves]) {
- // we need to reload all if the incremental diffs are not available
- [collectionView reloadData];
- } else {
- // if we have incremental diffs,tell the collection view to animate insertions and deletions
- [collectionView performBatchUpdates:^{
- NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
- if ([removedIndexes count]) {
- [collectionView deleteItemsAtIndexPaths:[removedIndexes aapl_indexPathsFromIndexesWithSection:0]];
- }
- NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
- if ([insertedIndexes count]) {
- [collectionView insertItemsAtIndexPaths:[insertedIndexes aapl_indexPathsFromIndexesWithSection:0]];
- }
- NSIndexSet *changedIndexes = [collectionChanges changedIndexes];
- if ([changedIndexes count]) {
- [collectionView reloadItemsAtIndexPaths:[changedIndexes aapl_indexPathsFromIndexesWithSection:0]];
- }
- } completion:NULL];
- }
- [self resetCachedAssets];
- }
- });
- }
我无法复制这个问题.可能是什么问题呢?非常感谢!
解决方法
我今天能够再现这个.为此,您需要:
>打开正在监听更改的应用程序
>打开照片应用程序,将一组照片从iCloud共享相册保存到您的照片库
>转到照片应用程序,删除其中的一些照片
>再次转到iCloud共享相册,并再次保存您删除的一些照片.你会看到这种情况发生.
我发现一个更新的代码似乎在这里更好地处理更新行为:
https://developer.apple.com/library/ios/documentation/Photos/Reference/PHPhotoLibraryChangeObserver_Protocol/
但是它仍然不会处理这种情况,也不会在要删除的索引更大时(即由于未捕获的异常’NSInternalInconsistencyException’终止应用程序),原因是:尝试从第0部分删除第9项,其中只包含9个更新前的项目).我创建了这个代码更新版本,处理这个更好,迄今为止还没有为我崩溃.
- func photoLibraryDidChange(changeInfo: PHChange!) {
- // Photos may call this method on a background queue;
- // switch to the main queue to update the UI.
- dispatch_async(dispatch_get_main_queue()) {
- // Check for changes to the list of assets (insertions,moves,or updates).
- if let collectionChanges = changeInfo.changeDetailsForFetchResult(self.assetsFetchResult) {
- // Get the new fetch result for future change tracking.
- self.assetsFetchResult = collectionChanges.fetchResultAfterChanges
- if collectionChanges.hasIncrementalChanges {
- // Get the changes as lists of index paths for updating the UI.
- var removedPaths: [NSIndexPath]?
- var insertedPaths: [NSIndexPath]?
- var changedPaths: [NSIndexPath]?
- if let removed = collectionChanges.removedIndexes {
- removedPaths = self.indexPathsFromIndexSetWithSection(removed,section: 0)
- }
- if let inserted = collectionChanges.insertedIndexes {
- insertedPaths = self.indexPathsFromIndexSetWithSection(inserted,section: 0)
- }
- if let changed = collectionChanges.changedIndexes {
- changedPaths = self.indexPathsFromIndexSetWithSection(changed,section: 0)
- }
- var shouldReload = false
- if changedPaths != nil && removedPaths != nil{
- for changedPath in changedPaths!{
- if contains(removedPaths!,changedPath){
- shouldReload = true
- break
- }
- }
- }
- if removedPaths?.last?.item >= self.assetsFetchResult.count{
- shouldReload = true
- }
- if shouldReload{
- self.collectionView.reloadData()
- }else{
- // Tell the collection view to animate insertions/deletions/moves
- // and to refresh any cells that have changed content.
- self.collectionView.performBatchUpdates(
- {
- if let theRemovedPaths = removedPaths {
- self.collectionView.deleteItemsAtIndexPaths(theRemovedPaths)
- }
- if let theInsertedPaths = insertedPaths {
- self.collectionView.insertItemsAtIndexPaths(theInsertedPaths)
- }
- if let theChangedPaths = changedPaths{
- self.collectionView.reloadItemsAtIndexPaths(theChangedPaths)
- }
- if (collectionChanges.hasMoves) {
- collectionChanges.enumerateMovesWithBlock() { fromIndex,toIndex in
- let fromIndexPath = NSIndexPath(forItem: fromIndex,inSection: 0)
- let toIndexPath = NSIndexPath(forItem: toIndex,inSection: 0)
- self.collectionView.moveItemAtIndexPath(fromIndexPath,toIndexPath: toIndexPath)
- }
- }
- },completion: nil)
- }
- } else {
- // Detailed change information is not available;
- // repopulate the UI from the current fetch result.
- self.collectionView.reloadData()
- }
- }
- }
- }
- func indexPathsFromIndexSetWithSection(indexSet:NSIndexSet?,section:Int) -> [NSIndexPath]?{
- if indexSet == nil{
- return nil
- }
- var indexPaths:[NSIndexPath] = []
- indexSet?.enumerateIndexesUsingBlock { (index,Bool) -> Void in
- indexPaths.append(NSIndexPath(forItem: index,inSection: section))
- }
- return indexPaths
- }
Swift 3 / iOS 10版本:
- func photoLibraryDidChange(_ changeInstance: PHChange) {
- guard let collectionView = self.collectionView else {
- return
- }
- // Photos may call this method on a background queue;
- // switch to the main queue to update the UI.
- DispatchQueue.main.async {
- guard let fetchResults = self.fetchResults else {
- collectionView.reloadData()
- return
- }
- // Check for changes to the list of assets (insertions,or updates).
- if let collectionChanges = changeInstance.changeDetails(for: fetchResults) {
- // Get the new fetch result for future change tracking.
- self.fetchResults = collectionChanges.fetchResultAfterChanges
- if collectionChanges.hasIncrementalChanges {
- // Get the changes as lists of index paths for updating the UI.
- var removedPaths: [IndexPath]?
- var insertedPaths: [IndexPath]?
- var changedPaths: [IndexPath]?
- if let removed = collectionChanges.removedIndexes {
- removedPaths = self.indexPaths(from: removed,section: 0)
- }
- if let inserted = collectionChanges.insertedIndexes {
- insertedPaths = self.indexPaths(from:inserted,section: 0)
- }
- if let changed = collectionChanges.changedIndexes {
- changedPaths = self.indexPaths(from: changed,section: 0)
- }
- var shouldReload = false
- if let removedPaths = removedPaths,let changedPaths = changedPaths {
- for changedPath in changedPaths {
- if removedPaths.contains(changedPath) {
- shouldReload = true
- break
- }
- }
- }
- if let item = removedPaths?.last?.item {
- if item >= fetchResults.count {
- shouldReload = true
- }
- }
- if shouldReload {
- collectionView.reloadData()
- } else {
- // Tell the collection view to animate insertions/deletions/moves
- // and to refresh any cells that have changed content.
- collectionView.performBatchUpdates({
- if let theRemovedPaths = removedPaths {
- collectionView.deleteItems(at: theRemovedPaths)
- }
- if let theInsertedPaths = insertedPaths {
- collectionView.insertItems(at: theInsertedPaths)
- }
- if let theChangedPaths = changedPaths {
- collectionView.reloadItems(at: theChangedPaths)
- }
- collectionChanges.enumerateMoves { fromIndex,toIndex in
- collectionView.moveItem(at: IndexPath(item: fromIndex,section: 0),to: IndexPath(item: toIndex,section: 0))
- }
- })
- }
- } else {
- // Detailed change information is not available;
- // repopulate the UI from the current fetch result.
- collectionView.reloadData()
- }
- }
- }
- }
- func indexPaths(from indexSet: IndexSet?,section: Int) -> [IndexPath]? {
- guard let set = indexSet else {
- return nil
- }
- return set.map { (index) -> IndexPath in
- return IndexPath(item: index,section: section)
- }
- }