SwiftUI-UIKit Interop
Bridge UIKit and SwiftUI in both directions: wrap UIKit views and controllers for use in SwiftUI, embed SwiftUI views into existing UIKit view hierarchies, and coordinate state updates safely. Targets Swift 6.3 / iOS 26+.
Contents
Bridging Directions
- UIKit into SwiftUI:
UIViewRepresentable: Wraps a custom UIView (e.g., text views, maps, custom controls).
UIViewControllerRepresentable: Wraps a UIViewController (e.g., camera controllers, document pickers, share sheets).
- SwiftUI into UIKit:
UIHostingController: Embeds SwiftUI views into UIKit view controller hierarchies.
UIHostingConfiguration: Embeds SwiftUI views directly into UICollectionView and UITableView cells (iOS 16+).
Representable Lifecycle and Coordinator
makeCoordinator() ──> makeUIView(context:) ──> updateUIView(uiView, context:) ──> dismantleUIView(uiView, coordinator:)
makeCoordinator(): Called once to create the delegate/coordinator object.
makeUIView(context:): Called once to instantiate the UIKit view and assign delegates.
updateUIView(_:context:): Called on every SwiftUI state change affecting the view. Must be idempotent.
dismantleUIView(_:coordinator:): Cleanup point when the view leaves the hierarchy. Invalidate timers, unregister observers.
State Synchronization and Feedback Loops
[!WARNING]
Prevent infinite update cycles:
When UIKit notifies the coordinator of a change (e.g., textViewDidChange), the coordinator updates SwiftUI state via @Binding. This triggers updateUIView.
Always check for value equality before applying updates to the UIKit view:
if uiView.text != text { uiView.text = text }
Embedding SwiftUI in UIKit
When adding a UIHostingController as a child view controller:
addChild(hostingController)
view.addSubview(hostingController.view)
- Set Auto Layout constraints
hostingController.didMove(toParent: self)
Use UIHostingConfiguration for modern cell layouts in UICollectionView/UITableView without manual controller management.
Route by Task
- For wrapping
MKMapView, UITextView, and camera capture controllers, read Map, Text, and Camera Wrappers.
- For
PHPickerViewController, MFMailComposeViewController, UIActivityViewController, and search controllers, read Picker, Mail, Share, and Search Wrappers.
- For
PDFView, QLPreviewController, and MFMessageComposeViewController, read PDF and Message Wrappers.
- For embedding SwiftUI in UIKit table/collection cells, navigation transitions, and full hosting migration, read Hosting Migration.
Common Mistakes
- Re-creating heavy UIKit objects inside
updateUIView instead of configuring the existing instance.
- Omitting equality checks in
updateUIView, triggering continuous render feedback loops.
- Adding a
UIHostingController's view without calling addChild and didMove(toParent:).
- Forgetting to clean up delegates, KVO, or NotificationCenter observers in
dismantleUIView.
- Ignoring safe area insets and sizing calculations (
sizeThatFits) in custom representables.
Review Checklist
References
1---2name: swiftui-uikit-interop3description: Bridges UIKit and SwiftUI with representables, hosting controllers/configurations, coordinators, and shared observable state. Use for wrapping UIKit or third-party views/controllers, embedding SwiftUI in UIKit, system controller surfaces, or incremental UIKit-to-SwiftUI migration.4---56# SwiftUI-UIKit Interop78Bridge UIKit and SwiftUI in both directions: wrap UIKit views and controllers for use in SwiftUI, embed SwiftUI views into existing UIKit view hierarchies, and coordinate state updates safely. Targets Swift 6.3 / iOS 26+.910## Contents1112- [Bridging Directions](#bridging-directions)13- [Representable Lifecycle and Coordinator](#representable-lifecycle-and-coordinator)14- [State Synchronization and Feedback Loops](#state-synchronization-and-feedback-loops)15- [Embedding SwiftUI in UIKit](#embedding-swiftui-in-uikit)16- [Route by Task](#route-by-task)17- [Common Mistakes](#common-mistakes)18- [Review Checklist](#review-checklist)19- [References](#references)2021## Bridging Directions22231. **UIKit into SwiftUI**:24 - `UIViewRepresentable`: Wraps a custom `UIView` (e.g., text views, maps, custom controls).25 - `UIViewControllerRepresentable`: Wraps a `UIViewController` (e.g., camera controllers, document pickers, share sheets).262. **SwiftUI into UIKit**:27 - `UIHostingController`: Embeds SwiftUI views into UIKit view controller hierarchies.28 - `UIHostingConfiguration`: Embeds SwiftUI views directly into `UICollectionView` and `UITableView` cells (iOS 16+).2930## Representable Lifecycle and Coordinator3132```33makeCoordinator() ──> makeUIView(context:) ──> updateUIView(uiView, context:) ──> dismantleUIView(uiView, coordinator:)34```3536- **`makeCoordinator()`**: Called once to create the delegate/coordinator object.37- **`makeUIView(context:)`**: Called once to instantiate the UIKit view and assign delegates.38- **`updateUIView(_:context:)`**: Called on **every** SwiftUI state change affecting the view. Must be idempotent.39- **`dismantleUIView(_:coordinator:)`**: Cleanup point when the view leaves the hierarchy. Invalidate timers, unregister observers.4041## State Synchronization and Feedback Loops4243> [!WARNING]44> Prevent infinite update cycles:45> When UIKit notifies the coordinator of a change (e.g., `textViewDidChange`), the coordinator updates SwiftUI state via `@Binding`. This triggers `updateUIView`.46> Always check for value equality before applying updates to the UIKit view:47> ```swift48> if uiView.text != text { uiView.text = text }49> ```5051## Embedding SwiftUI in UIKit5253When adding a `UIHostingController` as a child view controller:541. `addChild(hostingController)`552. `view.addSubview(hostingController.view)`563. Set Auto Layout constraints574. `hostingController.didMove(toParent: self)`5859Use `UIHostingConfiguration` for modern cell layouts in `UICollectionView`/`UITableView` without manual controller management.6061## Route by Task6263- For wrapping `MKMapView`, `UITextView`, and camera capture controllers, read [Map, Text, and Camera Wrappers](references/map-text-and-camera-wrappers.md).64- For `PHPickerViewController`, `MFMailComposeViewController`, `UIActivityViewController`, and search controllers, read [Picker, Mail, Share, and Search Wrappers](references/picker-mail-share-and-search-wrappers.md).65- For `PDFView`, `QLPreviewController`, and `MFMessageComposeViewController`, read [PDF and Message Wrappers](references/pdf-and-message-wrappers.md).66- For embedding SwiftUI in UIKit table/collection cells, navigation transitions, and full hosting migration, read [Hosting Migration](references/hosting-migration.md).6768## Common Mistakes6970- Re-creating heavy UIKit objects inside `updateUIView` instead of configuring the existing instance.71- Omitting equality checks in `updateUIView`, triggering continuous render feedback loops.72- Adding a `UIHostingController`'s view without calling `addChild` and `didMove(toParent:)`.73- Forgetting to clean up delegates, KVO, or NotificationCenter observers in `dismantleUIView`.74- Ignoring safe area insets and sizing calculations (`sizeThatFits`) in custom representables.7576## Review Checklist7778- [ ] `makeCoordinator` used for delegates, target-actions, and data sources79- [ ] `updateUIView` guards against redundant assignments to avoid feedback loops80- [ ] Child view controller containment calls (`addChild`, `didMove`) properly paired81- [ ] Cell layouts in UIKit use `UIHostingConfiguration` where available82- [ ] Subscribed observers and display links invalidated in `dismantleUIView`83- [ ] Auto Layout constraints configured with `translatesAutoresizingMaskIntoConstraints = false`8485## References8687- [Map, text, and camera representable recipes](references/map-text-and-camera-wrappers.md)88- [Picker, mail, share, and search recipes](references/picker-mail-share-and-search-wrappers.md)89- [PDF, QuickLook, and message composer recipes](references/pdf-and-message-wrappers.md)90- [Hosting migration and UIHostingController guide](references/hosting-migration.md)91- [UIViewRepresentable](https://sosumi.ai/documentation/swiftui/uiviewrepresentable)92- [UIViewControllerRepresentable](https://sosumi.ai/documentation/swiftui/uiviewcontrollerrepresentable)93- [UIHostingController](https://sosumi.ai/documentation/swiftui/uihostingcontroller)