I am using diffable data sources in a UICollectionView
using a layout of UICollectionViewCompositionalLayout.list
. My collection view supports reordering of cells via reorderingHandlers
on the UICollectionViewDiffableDataSource
. Additionally, I am mixing usage of NSDiffableDataSourceSnapshot
and NSDiffableDataSourceSectionSnapshot
, as is permitted in the documentation:
You can use section snapshots with or instead of an NSDiffableDataSourceSnapshot
I have noticed a strange error when I reorder cells after applying a NSDiffableDataSourceSnapshot
followed by a NSDiffableDataSourceSectionSnapshot
.
An excerpt from the UIViewController
is shown below:
override func viewDidLoad() {
super.viewDidLoad()
// Omitted the code to build the UICollectionView, add to the view, and assign its dataSource.
// Build and apply the initial snapshot, as a NSDiffableDataSourceSnapshot - NOT
// as a set of NSDiffableDataSourceSectionSnapshots.
// For this example, we just use some arbitrary test data.
var initialSnapshot = NSDiffableDataSourceSnapshot<Section, UUID>()
for section in Section.allCases {
initialSnapshot.appendSections([section])
initialSnapshot.appendItems([UUID(), UUID(), UUID()], toSection: section)
}
dataSource.apply(initialSnapshot, animatingDifferences: false)
// Then apply a section snapshot (same data as the initial snapshot).
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<UUID>()
sectionSnapshot.append(initialSnapshot.itemIdentifiers(inSection: .sectionTwo))
self.dataSource.apply(sectionSnapshot, to: .sectionTwo)
}
My data source is defined as:
private lazy var dataSource = makeDataSource()
func makeDataSource() -> UICollectionViewDiffableDataSource<Section, UUID> {
let cellRegistration = makeCellRegistration()
let dataSource = UICollectionViewDiffableDataSource<Section, UUID>(collectionView: collectionView) { view, indexPath, item in
view.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}
dataSource.reorderingHandlers.canReorderItem = { _ in true }
return dataSource
}
The full contents of my minimum reproducible example are contained in a small sample project. This includes the cell registration, building the UICollectionView
, adding it to the view, etc.
When I reorder any cells in a section other than the one that had the section snapshot applied, I get an assertion failure:
Assertion failure in
-[NSDiffableDataSourceSectionSnapshot snapshotOfParentItem:includingParentItem:]
, NSDiffableDataSourceSectionSnapshot.m:330
Terminating app due to uncaught exception '
NSInternalInconsistencyException
', reason: 'Invalid parameter not satisfying: index != NSNotFound'
The call stack, shown below, suggests that this is occurring within the framework in preparation of producing the post-reorder snapshot.
*** First throw call stack:
(
0 CoreFoundation 0x00007fff203fbbb4 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff2019ebe7 objc_exception_throw + 48
2 Foundation 0x00007fff20750c12 _userInfoForFileAndLine + 0
3 UIKitCore 0x00007fff24f97699 -[NSDiffableDataSourceSectionSnapshot snapshotOfParentItem:includingParentItem:] + 755
4 UIKitCore 0x00007fff24340b8c -[_UIDiffableDataSourceSectionSnapshotRebaser _rebaseForInitialSnapshot:finalSnapshot:initialSectionSnapshots:dataSourceDiffer:shouldPerformChildSnapshotMoves:] + 2368
5 UIKitCore 0x00007fff24340218 -[_UIDiffableDataSourceSectionSnapshotRebaser initWithInitialSnapshot:finalSnapshot:initialSectionSnapshots:dataSourceDiffer:shouldPerformChildSnapshotMoves:] + 226
6 UIKitCore 0x00007fff24f23c67 +[NSDiffableDataSourceTransaction _computeReorderingTransactionWithInitialSnapshot:reorderingUpdate:sectionSnapshotProvider:] + 2051
7 UIKitCore 0x00007fff24607f54 -[__UIDiffableDataSource _reorderingTransactionForReorderingUpdate:] + 187
8 UIKitCore 0x00007fff24607c42 -[__UIDiffableDataSource _commitReorderingForItemAtIndexPath:toDestinationIndexPath:shouldPerformViewAnimations:] + 136
9 libswiftUIKit.dylib 0x00007fff59345148 $s5UIKit34UICollectionViewDiffableDataSourceC010collectionC0_10moveItemAt2toySo0bC0C_10Foundation9IndexPathVAKtFTf4dnnn_n + 72
10 libswiftUIKit.dylib 0x00007fff5933ef65 $s5UIKit34UICollectionViewDiffableDataSourceC010collectionC0_10moveItemAt2toySo0bC0C_10Foundation9IndexPathVAKtFTo + 165
11 UIKitCore 0x00007fff2468137c -[UICollectionView _notifyDataSourceForMoveOfItemFromIndexPath:toIndexPath:] + 273
12 UIKitCore 0x00007fff246800cd -[UICollectionView _completeInteractiveMovementWithDisposition:completion:] + 1686
13 UIKitCore 0x00007fff2461be1c -[UICollectionViewListCell _reorderControlDidEndReordering:cancelled:] + 85
14 UIKitCore 0x00007fff2461e92b -[_UICollectionViewListCellReorderControl endReordering:] + 64
15 UIKitCore 0x00007fff2461e5bc -[_UICollectionViewListCellReorderControl pan:] + 414
16 UIKitCore 0x00007fff24ad0f8f -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 49
17 UIKitCore 0x00007fff24adb0e9 _UIGestureRecognizerSendTargetActions + 100
18 UIKitCore 0x00007fff24ad7c55 _UIGestureRecognizerSendActions + 294
19 UIKitCore 0x00007fff24ad6f91 -[UIGestureRecognizer _updateGestureForActiveEvents] + 725
20 UIKitCore 0x00007fff24ac9213 _UIGestureEnvironmentUpdate + 2713
21 UIKitCore 0x00007fff24ac82f2 -[UIGestureEnvironment _updateForEvent:window:] + 902
22 UIKitCore 0x00007fff250449c9 -[UIWindow sendEvent:] + 5273
23 UIKitCore 0x00007fff2501b4e8 -[UIApplication sendEvent:] + 825
24 UIKitCore 0x00007fff250b128a __dispatchPreprocessedEventFromEventQueue + 8695
25 UIKitCore 0x00007fff250b3a10 __processEventQueue + 8579
26 UIKitCore 0x00007fff250aa1b6 __eventFetcherSourceCallback + 240
27 CoreFoundation 0x00007fff20369e25 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
28 CoreFoundation 0x00007fff20369d1d __CFRunLoopDoSource0 + 180
29 CoreFoundation 0x00007fff203691f2 __CFRunLoopDoSources0 + 242
30 CoreFoundation 0x00007fff20363951 __CFRunLoopRun + 875
31 CoreFoundation 0x00007fff20363103 CFRunLoopRunSpecific + 567
32 GraphicsServices 0x00007fff2c851cd3 GSEventRunModal + 139
33 UIKitCore 0x00007fff24ffbe63 -[UIApplication _run] + 928
34 UIKitCore 0x00007fff25000a53 UIApplicationMain + 101
35 libswiftUIKit.dylib 0x00007fff5933d052 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
36 diffable-experiments 0x0000000100759fe8 $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 104
37 diffable-experiments 0x0000000100759f77 $s20diffable_experiments11AppDelegateC5$mainyyFZ + 39
38 diffable-experiments 0x000000010075a068 main + 24
39 dyld 0x0000000100788e1e start_sim + 10
40 ??? 0x0000000000000001 0x0 + 1
Am I doing anything wrong? Is there a workaround?