DKImagePickerController icon indicating copy to clipboard operation
DKImagePickerController copied to clipboard

NSInternalInconsistency crash in DKAssetGroupDetailVC

Open avinpr opened this issue 6 years ago • 2 comments

Bug:

Crash (NSInternalInconsistencyException) occurring in DKImagePickerController library when deleting photos from any album and re-engaging with app. The problem appears to be related to calling “performBatchUpdates” and receiving incorrect information on the updates that were made. This crash can also be reproduced in the sample app.

Steps to recreate:

  1. Start the sample app.
  2. Select any of the “Basic” options (eg. Pick Any, Single Select, Select All etc.)
  3. Select “Start” on the next screen to bring up the Image Picker screen.
  4. Select a photo on the Image Picker screen.
  5. Put the app in the background and navigate to the “Photos” app on the device.
  6. Delete the same photo that was previously selected within the sample app.
  7. Now, switch back to the sample app.
  8. It crashes right away.

Sample Error Message:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (47) must be equal to the number of items contained in that section before the update (48), plus or minus the number of items inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).

Excerpt from Stack trace:

CoreFoundation 0x0000000182527ef8 __exceptionPreprocess + 228 libobjc.A.dylib 0x00000001816f5a3c objc_exception_throw + 52 CoreFoundation 0x000000018243c068 +[NSException raise:format:arguments:] + 100 Foundation 0x0000000182f283dc -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 108 UIKitCore 0x00000001aed5db50 -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:] + 12836 UIKitCore 0x00000001aed64ddc -[UICollectionView _endUpdatesWithInvalidationContext:tentativelyForReordering:animator:] + 88 UIKitCore 0x00000001aed65114 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 384 UIKitCore 0x00000001aed64f70 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 92 UIKitCore 0x00000001aed64ef4 -[UICollectionView _performBatchUpdates:completion:invalidationContext:] + 80 UIKitCore 0x00000001aed64e30 -[UICollectionView performBatchUpdates:completion:] + 60 DKImagePickerController 0x0000000105a48424 function signature specialization <Arg[0] = Dead> of DKImagePickerController.DKAssetGroupDetailVC.imagePickerControllerDidDeselect(assets: [DKImagePickerController.DKAsset]) -> () + 280 DKImagePickerController 0x0000000105a43504 @objc DKImagePickerController.DKAssetGroupDetailVC.imagePickerControllerDidDeselect(assets: [DKImagePickerController.DKAsset]) -> () + 68 DKImagePickerController 0x0000000105a5c930 closure #1 () -> () in DKImagePickerController.DKImageBaseManager.notify(with: ObjectiveC.Selector, object: Swift.AnyObject?, objectTwo: Swift.AnyObject?) -> () + 280 DKImagePickerController 0x0000000105a5c6a8 DKImagePickerController.DKImageBaseManager.notify(with: ObjectiveC.Selector, object: Swift.AnyObject?, objectTwo: Swift.AnyObject?) -> () + 220 DKImagePickerController 0x0000000105a7c830 DKImagePickerController.DKImagePickerController.deselect(asset: DKImagePickerController.DKAsset) -> () + 1372 DKImagePickerController 0x0000000105a48774 function signature specialization <Arg[0] = Dead> of DKImagePickerController.DKAssetGroupDetailVC.group(groupId: Swift.String, didRemoveAssets: [DKImagePickerController.DKAsset]) -> () + 480 DKImagePickerController 0x0000000105a43590 @objc DKImagePickerController.DKAssetGroupDetailVC.group(groupId: Swift.String, didRemoveAssets: [DKImagePickerController.DKAsset]) -> () + 88 DKImagePickerController 0x0000000105a5c930 closure #1 () -> () in DKImagePickerController.DKImageBaseManager.notify(with: ObjectiveC.Selector, object: Swift.AnyObject?, objectTwo: Swift.AnyObject?) -> () + 280

Notes:

  • There was a PR recently that attempted to fix an issue with performBatchUpdates (https://github.com/zhangao0086/DKImagePickerController/pull/566) to explicitly call “numberOfItems(inSection:)” within DKAssetGroupDetailVC, but that doesn’t seem to have covered this issue.
  • Not using “performBatchUpdates” and instead keeping the enclosed block of code in place as-is seems to work well. However, I’m guessing that we’re losing some performance benefits that performBatchUpdates gives us around animation, but currently, I’m not seeing much visible impact even when having a few hundred files needing updates.
  • Verified crash occurs in iOS 11 & 12.

avinpr avatar Feb 06 '19 16:02 avinpr

@avinpr and I looked at this and he pointed out this was the original commit which introduced this for performBatchUpdates. @zhangao0086 do you know what the intent or use case was for this particular change?... In what scenario was the UI performance really poor?

devandanger avatar Feb 08 '19 17:02 devandanger

Hi @devandanger @avinpr This issue was fixed in the develop branch. Could you give it a try?

pod 'DKImagePickerController', :git => 'https://github.com/zhangao0086/DKImagePickerController.git', :branch => 'develop'

Then clean the project and rebuild

zhangao0086 avatar Feb 19 '19 06:02 zhangao0086