Duplication Allegations:
This question has wrongfully been flagged as a duplicate of another question I asked. This question here is about communicating changes TO the cell without entirely reloading it (to dynamically change its content instead of cross-fading to the new one), while the other is about structural ways of communicating information FROM the cell (to the view controller) as the cell's content is now abstracted away. That's two different things, thus this question is not a duplicate! Please reopen it. I do, however, realize that the question was not as clear as it should have been, which may have contributed to the fact so I've updated it.
iOS 14 introduced a new way to handle UICollectionViews
and cells by using UIContentConfiguration
, which holds the cell's data (source of truth). It's built so that the cell automatically refreshes whenever the data changes. But it refreshes the entire cell by cross-fading it to the new one. What if you want to have finer control over the update animations, e.g. when a name changes you want to only update that label, but not the entire cell?
Let's look at an example: You have a cell that shows the name
of a person and that person's car. The data comes from a model Person
and is loaded into the cell. The simplest way of passing the model to the cell would be via an ItemIdentifier
, something like:
struct Person {
var id: UUID
var name: String
var carName: String
}
...
enum Item {
case person(Person)
}
This way, whenever the Person
changes (e.g. the carName
changes), you can apply a new snapshot to the data source and the cell is updated. This update, however, takes place as a cross-fade animation between the old and new versions of the cell. What if you didn't want that? What if you wanted the cell to only animate the car name, for example, without "animating" the entire cell (aka "let the cell animate itself to fit in the new data")? That's not possible with this approach.
So, in order to prevent Person
changes from reloading entire cells, you have to adjust the ItemIdentifier
to not include the entire Person
struct but only its id or something:
enum Item {
case person(UUID)
}
Now, as long as the id doesn't change, the cell isn't reloaded, which is perfect and gives the cell opportunity to update Person
changes by itself. But how do you do that? Obviously, the cell now needs to grab the Person
data from somewhere else but how to communicate changes of Person
to that cell?
That's the question I'm trying to ask.
I recently posted a question related to this one. It's a "problem" I encountered while trying to solve the above question using Combine
publishers to provide the cell with updates:
(To be clear, that question is also not a duplicate. It's an entirely different problem just motivated by the same thing!)
This is quite old, but since it doesn't have a confirmed answer I will give this a go.
You can loop over visible cells. The list shouldn't be that long and therefore the solution should be quite efficient.