Use SwiftUI With UIKit – WWDC2022
#iOS App Development
To be honest, from this talk I was expecting to get something more. Meaning that... well we did know that SwiftUI view is wrapped into and its lifecycle is managed by UIHostingViewController. And we did know that ObservableObjects trigger SwiftUI refresh...
Anyway, here is the summary.
In iOS16 new self-sizing options for UIHostingViewController were added, allowing it to be added as a child view controller as we did with plain old view controllers.
Bridging Data from App to SwiftUI
There are at least two ways to update the views hosted inside UIHostingViewController. The first one is manual:
The second way to keep the UI in sync is to use ObservableObjects. First, we make our model to ObservableObject
protocol and pass it to SwiftUI view as a dependency:
Then we pass it to the SwiftUI view when creating a host view controller:
SwiftUI in Cells
UIHostingConfiguration
The brand new UIHostingConfiguration feature allows to host SwiftUI views inside UICollectionView and UITableVIewCells:
Looks like somewhere under the hood it creates and reuses UIHostingViewController with sizingOptions
assigned to .preferredContentSize
.
The following videos are recommended to watch:
- [[Modern cell configuration - WWDC2020]]
- [[Hello Swift Charts - WWDC2022]]
Margins
An important point is how UIKit cells with embedded SwiftUI views handle margins for its content. There is some default value applied, but allows to configure it by using margins(...)
modifier:
Background
There is also a way to paint the background with (quite unexpectedly) background modifier:
Here is how the background modifier affects the cell (quite expectedly):
Swipes
SwiftUI cells hosting configuration also allows handling swipes. We were warned 100 times to avoid using IndexPath
in handlers because it will lead to a mess due to the cells' reusable nature. That's what we knew before, didn't we?
Configuration update handler
Here is an example of how to use configurationUdpateHandler with UIHostingConfiguration
:
Cells Data flow
Apple's recommendation is to use DiffableDataSource
only for handling collection updates like insertion, deletion, and item moves by using items' ids.
For individual items updates handling, they recommend using ObservableObject
.
This is all quite understandable.
It's possible to use UICollectionViewDataSource
not only with items' ids but to treat the entire item as a Hashable
thing. This will allow not only to handle collection-wise updates but also individual items refresh. In that case, the changed item would be actually treated as deleted and inserted back.
And this is a very reliable way to handle collections in sync with the UI simply because there is no place for mistakes: you always show what you have in the collection.
The downside of this solution is that it causes the cell to reload completely. To be more exact, it triggers the cell to deletion and re-insert.
When using a pure UIKit cell that was affordable, at least I've never faced any issues with that. However, with cells backed with SwiftUI, it looks like not. Anyway, this is expectable, because every UIHostingConfiguration
cell is likely to have an entire UIHostingViewController under the hood.
Hopefully, a brand new A17 Bionic chip would be capable to handle that, lol.
Self-sizing cells
The most wanted feature since iOS8 is still with us.
Another recommendation to watch: What's new in UIKit – WWDC2022
Bridging Data from SwiftUI to UIKit
The provided way to handle mutation made in SwiftUI is simply ObservableObject
's 2-ways binding:
Key Takeaways
- Use UIHostingViewController to host SwiftUI views
- Use UIHostingConfiguration to host SwiftUI views in Cells
- Use observable objects for 2-way data binding
Comments