I am using UIHostingConfiguration
to embed SwiftUI Views in a UICollectionView
like this:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.contentConfiguration = UIHostingConfiguration {
CellView()
}
Any @State var
declarations in CellView
or its subviews are being initialized to essentially random values. This seems to completely break the way @State
works in SwiftUI. I have been able to reproduce it in this pretty simple sample project. Here is a video illustrating the problem. The count for each cell should be initialized to 0, but incrementing the count in any cell causes other cells to display a non-zero count when they are allocated.
I think this happens because when the collection view dequeues a reusable cell it is mem-copying another cell's view and the @State var
holds the value from the previous cell. This is how collection view cells work in UIKit, but UICollectionViewCell
s have a prepareForReuse
function which is supposed to clean up and reinitialize cell state, but I can't fine a similar mechanism in SwiftUI.
How can I reinitialize @State var
s in my Views whenever the collection view is dequeuing a cell, and not unnecessarily at other times (like View.init
which is called much more frequently)?
EDIT: Ideally I'm looking for a solution that doesn't require code in every SwiftUI View that is in a UIHostingConfiguration, since that will be easy for humans forget.
One solution is to break UICollectionView's cell reuse by using unique identifiers for every cell like this:
let cellReuseID = model.identifier ?? "error"
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellReuseID)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseID, for: indexPath)
This ensures @State
variables play by the rules and are initialized to the value you specify before they are displayed every time. Obviously this incurs a performance cost, but in my case the difference is not noticeable. For me this is preferable to playing whack-a-mole with this bug every time someone adds a @State var to any view in our complex cell hierarchy and forgets about this problem.