Heuristic
Heuristic

Reputation: 5341

UICollectionView snapshot takes too long to RE-apply

I have a UICollectionView with a large set of data source, e.g. 30000+ items; And the data source varies depending on screen orientation (ie. portrait, landscape), so I re-create and re-apply the snapshot whenever screen rotates.

What I noticed, is that the first time UICollectionView loads cells it's relatively quick, but subsequently re-applying different snapshots (after screen rotation) takes a long time.

This is understandable because subsequent reload need lots of computing for the diff of existing and new snapshots, so I wonder, if there's a way to apply snapshots without calculating the diffs? I don't want to keep two copies of snapshot in memory because of the size of them. Or can I workaround this by first applying an empty snapshot before applying the full sized one?

Thanks!

Edit:

I did some rough test:

With Empty Snapshot

First Load:

2022-08-05 07:47:11.666847+1000 before apply
2022-08-05 07:47:11.667139+1000 after apply empty snapshot
2022-08-05 07:47:11.788821+1000 after creating full-sized snapshot
2022-08-05 07:47:13.022973+1000 after applying full-sized snapshot

total: ~1.36

Reload after rotation:

2022-08-05 07:48:05.238174+1000 before apply
2022-08-05 07:48:08.708084+1000 after apply empty snapshot
2022-08-05 07:48:08.900322+1000 after creating full-sized snapshot
2022-08-05 07:48:12.034542+1000 after applying full-sized snapshot

total: ~6.80

Without Empty Snapshot

First Load:

2022-08-05 07:49:33.149233+1000 Setting columns…
2022-08-05 07:49:33.279147+1000 before apply
2022-08-05 07:49:33.401114+1000 after creating full-sized snapshot
2022-08-05 07:49:34.402645+1000 after applying full-sized snapshot

total: ~1.25

Reload after rotation:

2022-08-05 07:50:26.829309+1000 Reload due to trait collection change…
2022-08-05 07:50:27.270996+1000 Setting columns…
2022-08-05 07:50:31.187630+1000 before apply
2022-08-05 07:50:31.410154+1000 after creating full-sized snapshot
2022-08-05 07:50:45.879088+1000 after applying full-sized snapshot

total: ~19.05

Conclusion:

So the question remains: is there any way to make it quick? If not I may need to go back to the old UICollectionViewDataSource way of providing cells.

Upvotes: 1

Views: 691

Answers (1)

ChrisBob
ChrisBob

Reputation: 338

Using dataSource.applySnapshotUsingReloadData() is much faster than apply(_, animatingDifferences: ) and is especially for the case where you are changing a lot of data because it does not compute a diff. I eliminated a 3+ second lag in my own code handling 30k+ rows by making this change.

https://developer.apple.com/documentation/uikit/uicollectionviewdiffabledatasource/3804469-applysnapshotusingreloaddata

Note that it is only available on iOS 15 or later, so if you still need to support older versions you may need to wrap as such:

if #available(iOS 15, *) {
    self?.dataSource.applySnapshotUsingReloadData(snapshot)
} else {
    self?.dataSource.apply(snapshot, animatingDifferences: false)
}

Upvotes: 0

Related Questions