With iOS 26, Apple brought one of the most beloved features of SwiftUI to UIKit—the long-awaited ability to observe state directly in the UI layer. Combined with the new updateProperties()
lifecycle method, UIKit developers can now enjoy the reactive programming benefits that SwiftUI developers have been raving about for years.
Before iOS 26
Prior to iOS 26, updating the UI in UIKit typically relied on methods like the ones shown below.
final class ViewController: UIViewController {
private var data: UserData? {
didSet { updateUI() }
}
private func updateUI() {
usernameLabel.text = data?.username
userImageView.image = data?.image
setNeedsLayout()
}
}
If the updateUI
method was not called, the user interface would not update accordingly. On the other hand, calling it too frequently could negatively impact performance. Fortunately, this long-standing dilemma has finally been resolved.
Introducing Automatic Observation Tracking
iOS 26 introduces Swift's @Observable
macro to UIKit, offering full automatic tracking capabilities. When observable properties are accessed within designated UIKit methods, the framework automatically establishes dependencies and ensures that views are invalidated and updated when those properties change.
@Observable class DataModel {
var image: UIImage
var username: String
}
final class UserViewController: UIViewController {
var dataModel: DataModel
var usernameLabel: UILabel
var userImage: UIImageView
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// UIKit automatically tracks these properties
userImage.image = dataModel.image
usernameLabel.text = dataModel.username
}
}
There is no longer a need to call setNeedsLayout()
or manually trigger update methods. By simply applying the @Observable
macro to your data class and implementing the viewWillLayoutSubviews
method, UIKit will:
- Automatically track dependencies such as
image
andusername
during the initial layout, - Invalidate the view when these properties change, and
- Reinvoke
viewWillLayoutSubviews()
to ensure the UI remains in sync.
Makes CollectionView Usage Easier
@Observable class ItemModel {
var title: String
var subtitle: String
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
let itemModel = itemModel(for: indexPath)
cell.configurationUpdateHandler = { cell, state in
var content = UIListContentConfiguration.subtitleCell()
content.text = listItemModel.title
content.secondaryText = listItemModel.subtitle
cell.contentConfiguration = content
}
return cell
}
Ready to modernize your UIKit apps?
To take full advantage of the new reactive capabilities introduced in iOS 26, begin by updating your project to the iOS 26 SDK and recompiling your existing applications.
Next, identify areas in your codebase that rely on manual UI update patterns. Convert suitable data models to use the @Observable
macro, and implement the updateProperties()
method to handle property-specific update logic. For enhanced UI responsiveness and smoother animations, utilize flushUpdates()
where appropriate.
UIKit is entering a new era—more reactive, performant, and developer-friendly than ever before. Welcome to the future of iOS development.