Diffable Data Source - Reload Header
Asked Answered
D

2

5

What are the ways in which a UICollectionViewDiffableDataSource header can be reloaded?

I have a collection view with a header that displays user details, and rows that display posts, the model is

struct PostUser {
    var user: User
    var post: Post
}

when I change a property via the snapshot

    var postUsers = [PostUser]() {
        didSet {
            self.applySnapshot(postUsers)
        }
    }

    fileprivate func applySnapshot(_ postsUser: [PostUser]) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, PostUser>()
        snapshot.appendSections([.main])
        snapshot.appendItems(postsUser)
        self.datasource.apply(snapshot, animatingDifferences: true)
    }

the rows reload, however the supplementary header does not. The only way I can get the header to change is if I make the Section part of the model, so:

    struct Section: Hashable {
        var User: User
    }

my apply snapshot now becomes

    fileprivate func applySnapshot(_ postsUser: [PostUser]) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, PostUser>()
        snapshot.appendSections([Section(User: self.user)])
        snapshot.appendItems(postsUser)
        self.datasource.apply(snapshot, animatingDifferences: true)
    }

I then set the user separately

    var user: User! = nil {
        didSet {
            self.applySnapshot(self.postUsers)
        }
    }

and the header reloads.

I don't quite understand why when I change something in postUsers, the rows reload, but the header does not - until I implement a model as part of the section?

I do understand that diffable works on hashing, and so when I change a property, the table reloads, but it feels like the header should also reload, but it is treated separately?

Daubery answered 8/9, 2020 at 8:27 Comment(0)
A
5

Headers are only reloaded when a change in the section itself is detected. If only the items change, the supplementary views will remain unchanged. Another thing you could look into depending on your case would be to set animatingDifferences to false when you want to reload a header since, as of the latest iOS 14 beta, that will trigger reloadData. No diffing will be done.

Amazon answered 8/9, 2020 at 8:35 Comment(2)
On iOS 15, this advice should change to calling applySnapshotUsingReloadData insteadOutsole
Yes, iOS 15 introduces lots of improvements around reloading and diffing now always happens no matter the animations so definitely disregard my answer if you're targeting iOS 15+Amazon
R
2

I figure out to use reloadSections for iOS 15 previous is workable.

private func applyNewSnapshot() {
    var newSnapshot = self.dataSource.snapshot()
    if #available(iOS 15.0, *) {
        self.dataSource.applySnapshotUsingReloadData(newSnapshot)
    } else {
        // Fallback on earlier versions
        newSnapshot.reloadSections([.main])
        self.dataSource.apply(newSnapshot, animatingDifferences: false)
    }
}
Rhythmical answered 26/6, 2023 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.