Specify queue for collapse/expand of section snapshots

Is there any way to use outline disclosure sections in a UICollectionViewDiffableDataSource without having to make all apply(_ snapshot:) calls from the main thread?

Whenever I collapse or expand a section I get a warning about mixing main queue/off-main queue updates:

Warning: applying updates in a non-thread confined manner is dangerous and can lead to deadlocks. Please always submit updates either always on the main queue or always off the main queue

I understand what this means, but I am applying my section snapshots on a background queue to avoid interrupting the UI, it seems like the expand/collapse updates use the main queue and I cannot find any way to make it use the same queue as my other updates. Does this mean I must apply my own updates on the main queue now as well?

Answered by Frameworks Engineer in 791341022

Currently, you do need to apply snapshots on the main queue when using certain features (such as outline disclosure expand/collapse support, or interactive item reordering) where the user is directly manipulating the collection view and an immediate UI update is expected in response.

In general, applying snapshots from a background queue is almost always unnecessary in general. The only work that happens off the main queue when you apply a snapshot from a background queue is the diffing of old & new snapshots, and the diffing is very efficient (as long as you are using proper identifiers that correctly and efficiently implement hashing & equality). Most of the work involved in performing updates actually occurs in the UICollectionView, where it needs to process all of the updates from the diffable data source, and then generate the necessary cell animations — this work always needs to happen on the main queue no matter what. Therefore, it's recommended to simply always apply snapshots on the main queue in general.

You should only ever consider whether applying snapshots on a background queue might help if you observe noticeable performance issues (short hangs/stalls of the main queue) when applying snapshots, and then confirm using a Time Profiler trace in Instruments that the bottleneck is actually the diffing of identifiers itself, which is extremely uncommon. Usually there is some other issue that bubbles up first that needs to be addressed, and applying snapshots from a background queue won't make a significant difference.

Currently, you do need to apply snapshots on the main queue when using certain features (such as outline disclosure expand/collapse support, or interactive item reordering) where the user is directly manipulating the collection view and an immediate UI update is expected in response.

In general, applying snapshots from a background queue is almost always unnecessary in general. The only work that happens off the main queue when you apply a snapshot from a background queue is the diffing of old & new snapshots, and the diffing is very efficient (as long as you are using proper identifiers that correctly and efficiently implement hashing & equality). Most of the work involved in performing updates actually occurs in the UICollectionView, where it needs to process all of the updates from the diffable data source, and then generate the necessary cell animations — this work always needs to happen on the main queue no matter what. Therefore, it's recommended to simply always apply snapshots on the main queue in general.

You should only ever consider whether applying snapshots on a background queue might help if you observe noticeable performance issues (short hangs/stalls of the main queue) when applying snapshots, and then confirm using a Time Profiler trace in Instruments that the bottleneck is actually the diffing of identifiers itself, which is extremely uncommon. Usually there is some other issue that bubbles up first that needs to be addressed, and applying snapshots from a background queue won't make a significant difference.

Thank you for your reply, I will certainly investigate the issues you mention. For my use case it definitely does feel like the diffing is the issue, I have a large number of items (tens of thousands) and a large number of sections (100+) which becomes slow for large numbers of sections quite quickly.

For the curious, it turns out there is a way to get the section snapshot collapse/expansion to be triggered from an arbitrary queue and that is to use the sectionSnapshotHandlers. I have been able to override shouldExpandItem and shouldCollapseItem to make the necessary snapshot changes from my background queue using the expand() and collapse() methods on NSDiffableDataSourceSectionSnapshot, doing this avoids the thread confinement warnings.

Specify queue for collapse/expand of section snapshots
 
 
Q