NSCollectionViewDiffableDataSource crashes when applying snapshot with different sections to previous snapshot

Originator:dcutting
Number:rdar://FB7537097 Date Originated:15/Jan/2020
Status:Open Resolved:
Product:AppKit Product Version:Catalina
Classification:Crash Reproducible:Yes
 
I’m trying to create an NSCollectionView using the new NSCollectionViewDiffableDataSource on macOS.

I am dynamically loading/changing the sections and items over an API so the sections will potentially change with every update. My section and item identifier models are Hashable with UUIDs as recommended in the WWDC video.

I get a crash when I try to apply a snapshot and animate the changes in the recommended way.

You can see a StackOverflow question that has exactly the same problem as me and includes a sample project: https://stackoverflow.com/questions/58792252/appending-sections-in-nscollectionviewdiffabledatasource

But this is the gist of it:

```swift
    private func updateDataSource(sections: [Section]) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        for section in sections {
            snapshot.appendSections([section])
            snapshot.appendItems(section.items, toSection: section)
        }
        self.dataSource.apply(snapshot, animatingDifferences: true)
    }
```

I get a crash on the line where I apply the snapshot:

```
2020-01-15 21:53:10.623388+0000 Lux-Mac[28949:943873] [General] An uncaught exception was raised
2020-01-15 21:53:10.623441+0000 Lux-Mac[28949:943873] [General] -[NSCollectionView insertSections:] Section index 1 out of bounds
2020-01-15 21:53:10.623532+0000 Lux-Mac[28949:943873] [General] (
	0   CoreFoundation                      0x00007fff336518ab __exceptionPreprocess + 250
	1   libobjc.A.dylib                     0x00007fff69729805 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff33651701 +[NSException raise:format:] + 189
	3   UIFoundation                        0x00007fff64273d93 -[_NSCollectionViewCore insertSections:] + 267
	4   UIFoundation                        0x00007fff6423db2e -[_NSDiffableDataSourceViewUpdater _performNSCollectionViewInsertUpdate:] + 222
	5   UIFoundation                        0x00007fff6423d903 -[_NSDiffableDataSourceViewUpdater _performViewUpdates:] + 594
	6   AppKit                              0x00007fff3110086c __58-[NSCollectionView performBatchUpdates:completionHandler:]_block_invoke + 21
	7   UIFoundation                        0x00007fff6427ec1d -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 323
	8   UIFoundation                        0x00007fff6427eab7 -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 90
	9   UIFoundation                        0x00007fff6427ea3a -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:] + 74
	10  UIFoundation                        0x00007fff6427e98f -[_NSCollectionViewCore performBatchUpdates:completion:] + 53
	11  AppKit                              0x00007fff31100778 -[NSCollectionView performBatchUpdates:completionHandler:] + 282
	12  UIFoundation                        0x00007fff6423d0ce -[_NSDiffableDataSourceViewUpdater _performUpdateWithCollectionViewUpdateItems:dataSourceSnapshotter:updateHandler:completion:] + 528
	13  UIFoundation                        0x00007fff6429a41e -[__NSDiffableDataSource _commitNewDataSource:withViewUpdates:completion:] + 265
	14  UIFoundation                        0x00007fff64294e35 __66-[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:]_block_invoke.259 + 190
	15  UIFoundation                        0x00007fff6429514e __66-[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:]_block_invoke.284 + 170
	16  libdispatch.dylib                   0x000000010088078f _dispatch_client_callout + 8
	17  libdispatch.dylib                   0x00000001008914cb _dispatch_lane_barrier_sync_invoke_and_complete + 135
	18  UIFoundation                        0x00007fff642948a9 -[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:] + 842
	19  UIFoundation                        0x00007fff64322d8f +[_NSUIAnimator performWithAnimation:] + 90
	20  UIFoundation                        0x00007fff64295ab5 -[__NSDiffableDataSource applyDifferencesFromSnapshot:animatingDifferences:completion:] + 158
	21  libswiftAppKit.dylib                0x00007fff69ec4bb3 $s6AppKit34NSCollectionViewDiffableDataSourceC5apply_20animatingDifferences10completionyAA010NSDiffablefG8SnapshotVyxq_G_SbyycSgtF + 211
	22  Lux-Mac                             0x0000000100014fdc $s7Lux_Mac25YearBrowserViewControllerC16updateDataSource33_EF98DAE265F06E6EB66B46FEA4E9CD66LL_9animatingySayAA0C0VG_SbtF + 3196
	23  Lux-Mac                             0x00000001000141df $s7Lux_Mac25YearBrowserViewControllerC04loadE0yyFySayAA0C0VGcfU_ + 63
	24  Lux-Mac                             0x000000010001425f $sSay7Lux_Mac4YearVGIegg_ADIegn_TR + 15
	25  Combine                             0x00007fff327f3083 $s7Combine11SubscribersO4SinkC7receiveyAC6DemandVxF + 35
	26  Combine                             0x00007fff327f32c0 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receiveyAC6DemandV5InputQzFTW + 16
	27  Combine                             0x00007fff328274a8 $s7Combine10PublishersO9ReceiveOnV5Inner33_1178A6B2012BC46DB46053E713A746B4LLC7receiveyAA11SubscribersO6DemandV6OutputQzFyycfU_ + 248
	28  Combine                             0x00007fff3282a4b1 $s7Combine10PublishersO9ReceiveOnV5Inner33_1178A6B2012BC46DB46053E713A746B4LLC7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tFyycfU_TATm + 49
	29  libswiftFoundation.dylib            0x00007fff6a5ddfa9 $sIeg_IeyB_TR + 25
	30  CoreFoundation                      0x00007fff335d57ab __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
	31  CoreFoundation                      0x00007fff335d56ed __CFRunLoopDoBlocks + 379
	32  CoreFoundation                      0x00007fff335d4d30 __CFRunLoopRun + 2792
	33  CoreFoundation                      0x00007fff335d3bd3 CFRunLoopRunSpecific + 499
	34  HIToolbox                           0x00007fff3212a65d RunCurrentEventLoopInMode + 292
	35  HIToolbox                           0x00007fff3212a2a9 ReceiveNextEventCommon + 356
	36  HIToolbox                           0x00007fff3212a127 _BlockUntilNextEventMatchingListInModeWithFilter + 64
	37  AppKit                              0x00007fff3079beb4 _DPSNextEvent + 990
	38  AppKit                              0x00007fff3079a690 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
	39  AppKit                              0x00007fff3078c3ae -[NSApplication run] + 658
	40  AppKit                              0x00007fff3075e775 NSApplicationMain + 777
	41  Lux-Mac                             0x000000010002c94d main + 13
	42  libdyld.dylib                       0x00007fff6aa977fd start + 1
	43  ???                                 0x0000000000000003 0x0 + 3
)
2020-01-15 21:53:10.624371+0000 Lux-Mac[28949:943873] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[NSCollectionView insertSections:] Section index 1 out of bounds'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff336518ab __exceptionPreprocess + 250
	1   libobjc.A.dylib                     0x00007fff69729805 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff33651701 +[NSException raise:format:] + 189
	3   UIFoundation                        0x00007fff64273d93 -[_NSCollectionViewCore insertSections:] + 267
	4   UIFoundation                        0x00007fff6423db2e -[_NSDiffableDataSourceViewUpdater _performNSCollectionViewInsertUpdate:] + 222
	5   UIFoundation                        0x00007fff6423d903 -[_NSDiffableDataSourceViewUpdater _performViewUpdates:] + 594
	6   AppKit                              0x00007fff3110086c __58-[NSCollectionView performBatchUpdates:completionHandler:]_block_invoke + 21
	7   UIFoundation                        0x00007fff6427ec1d -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 323
	8   UIFoundation                        0x00007fff6427eab7 -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 90
	9   UIFoundation                        0x00007fff6427ea3a -[_NSCollectionViewCore _performBatchUpdates:completion:invalidationContext:] + 74
	10  UIFoundation                        0x00007fff6427e98f -[_NSCollectionViewCore performBatchUpdates:completion:] + 53
	11  AppKit                              0x00007fff31100778 -[NSCollectionView performBatchUpdates:completionHandler:] + 282
	12  UIFoundation                        0x00007fff6423d0ce -[_NSDiffableDataSourceViewUpdater _performUpdateWithCollectionViewUpdateItems:dataSourceSnapshotter:updateHandler:completion:] + 528
	13  UIFoundation                        0x00007fff6429a41e -[__NSDiffableDataSource _commitNewDataSource:withViewUpdates:completion:] + 265
	14  UIFoundation                        0x00007fff64294e35 __66-[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:]_block_invoke.259 + 190
	15  UIFoundation                        0x00007fff6429514e __66-[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:]_block_invoke.284 + 170
	16  libdispatch.dylib                   0x000000010088078f _dispatch_client_callout + 8
	17  libdispatch.dylib                   0x00000001008914cb _dispatch_lane_barrier_sync_invoke_and_complete + 135
	18  UIFoundation                        0x00007fff642948a9 -[__NSDiffableDataSource applyDifferencesFromSnapshot:completion:] + 842
	19  UIFoundation                        0x00007fff64322d8f +[_NSUIAnimator performWithAnimation:] + 90
	20  UIFoundation                        0x00007fff64295ab5 -[__NSDiffableDataSource applyDifferencesFromSnapshot:animatingDifferences:completion:] + 158
	21  libswiftAppKit.dylib                0x00007fff69ec4bb3 $s6AppKit34NSCollectionViewDiffableDataSourceC5apply_20animatingDifferences10completionyAA010NSDiffablefG8SnapshotVyxq_G_SbyycSgtF + 211
	22  Lux-Mac                             0x0000000100014fdc $s7Lux_Mac25YearBrowserViewControllerC16updateDataSource33_EF98DAE265F06E6EB66B46FEA4E9CD66LL_9animatingySayAA0C0VG_SbtF + 3196
	23  Lux-Mac                             0x00000001000141df $s7Lux_Mac25YearBrowserViewControllerC04loadE0yyFySayAA0C0VGcfU_ + 63
	24  Lux-Mac                             0x000000010001425f $sSay7Lux_Mac4YearVGIegg_ADIegn_TR + 15
	25  Combine                             0x00007fff327f3083 $s7Combine11SubscribersO4SinkC7receiveyAC6DemandVxF + 35
	26  Combine                             0x00007fff327f32c0 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receiveyAC6DemandV5InputQzFTW + 16
	27  Combine                             0x00007fff328274a8 $s7Combine10PublishersO9ReceiveOnV5Inner33_1178A6B2012BC46DB46053E713A746B4LLC7receiveyAA11SubscribersO6DemandV6OutputQzFyycfU_ + 248
	28  Combine                             0x00007fff3282a4b1 $s7Combine10PublishersO9ReceiveOnV5Inner33_1178A6B2012BC46DB46053E713A746B4LLC7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tFyycfU_TATm + 49
	29  libswiftFoundation.dylib            0x00007fff6a5ddfa9 $sIeg_IeyB_TR + 25
	30  CoreFoundation                      0x00007fff335d57ab __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
	31  CoreFoundation                      0x00007fff335d56ed __CFRunLoopDoBlocks + 379
	32  CoreFoundation                      0x00007fff335d4d30 __CFRunLoopRun + 2792
	33  CoreFoundation                      0x00007fff335d3bd3 CFRunLoopRunSpecific + 499
	34  HIToolbox                           0x00007fff3212a65d RunCurrentEventLoopInMode + 292
	35  HIToolbox                           0x00007fff3212a2a9 ReceiveNextEventCommon + 356
	36  HIToolbox                           0x00007fff3212a127 _BlockUntilNextEventMatchingListInModeWithFilter + 64
	37  AppKit                              0x00007fff3079beb4 _DPSNextEvent + 990
	38  AppKit                              0x00007fff3079a690 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
	39  AppKit                              0x00007fff3078c3ae -[NSApplication run] + 658
	40  AppKit                              0x00007fff3075e775 NSApplicationMain + 777
	41  Lux-Mac                             0x000000010002c94d main + 13
	42  libdyld.dylib                       0x00007fff6aa977fd start + 1
	43  ???                                 0x0000000000000003 0x0 + 3
)
libc++abi.dylib: terminating with uncaught exception of type NSException
```

I do not get a crash if I don’t animate the changes, or if I don’t change the sections between snapshots.

I have ported the code to iOS/UIKit and it works fine, so this looks like a bug in the macOS implementation of NSCollectionViewDiffableDataSource.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!