Logo for tanaschita.com

How to use SwiftUI Coordinators to communicate with UIKit

Bridging UIKit delegates and events back into SwiftUI.

09 Feb 2026 · 5 min read

When building SwiftUI apps, we sometimes still need UIKit. Maybe we're integrating an older code base or using system controllers that don't yet have a native SwiftUI equivalent.

In those cases, we can wrap UIKit views or view controllers using UIViewControllerRepresentable. But as soon as delegates or callbacks are involved, we need a way to communicate back to SwiftUI. That's where coordinators come in.

Let's look at a practical example.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

The goal

Suppose we want to use Apple's DataScannerViewController to scan QR codes. At the time of writing, DataScannerViewController does not have a native SwiftUI equivalent yet.

From SwiftUI, we want to:

  • present the scanner
  • scan a code
  • pass the scanned value back to SwiftUI state

Wrapping the view controller

To embed a UIKit view controller inside SwiftUI, we conform to UIViewControllerRepresentable:

struct ScannerView: UIViewControllerRepresentable {
@Binding var code: String?
func makeUIViewController(context: Context) -> DataScannerViewController {
let controller = DataScannerViewController(
recognizedDataTypes: [.barcode(symbologies: [.qr])]
)
return controller
}
func updateUIViewController(_ uiViewController: DataScannerViewController, context: Context) {
}
}

Now we can present it like any other SwiftUI view:

struct ContentView: View {
@State private var code: String?
@State private var showingScanner = false
var body: some View {
VStack {
Text(code ?? "")
Button("Scan QR code") {
showingScanner = true
}
}
.sheet(isPresented: $showingScanner) {
ScannerView(code: $code)
}
}
}

So far, the code binding we pass into the scanner view never gets updated by it. To be able to do that, we need to setup the scanner view controller's delegate at first.

Why we need a coordinator

UIKit delegates require a reference type (class). But SwiftUI views are structs. So our ScannerView cannot directly act as the delegate.

SwiftUI solves this mismatch by providing coordinators which act as small bridge objects that:

  • conform to delegates
  • receive UIKit callbacks
  • forward data back to SwiftUI

Creating a coordinator

Every representable can define a nested Coordinator type and a makeCoordinator() method:

struct ScannerView: UIViewControllerRepresentable {
@Binding var code: String?
func makeCoordinator() -> Coordinator {
Coordinator(code: $code)
}
class Coordinator {
@Binding var code: String?
init(code: Binding<String?>) {
_code = code
}
}
}

SwiftUI keeps this coordinator alive for the lifetime of the representable.

Conforming to the delegate

We can then extend the coordinator to serve as DataScannerViewControllerDelegate:

class Coordinator: DataScannerViewControllerDelegate {
@Binding var code: String?
init(code: Binding<String?>) {
_code = code
}
func dataScanner(_ dataScanner: DataScannerViewController, didAdd addedItems: [RecognizedItem], allItems: [RecognizedItem]) {
guard let item = allItems.first else { return }
switch item {
case .barcode(let code):
code = code.payloadStringValue
default: break
}
}
}

Now the coordinator receives scan results and updates the binding.

Connecting everything

Finally, we assign the delegate inside makeUIViewController:

func makeUIViewController(context: Context) -> DataScannerViewController {
let controller = DataScannerViewController(
recognizedDataTypes: [.barcode(symbologies: [.qr])]
)
controller.delegate = context.coordinator
try? controller.startScanning()
return controller
}

context.coordinator gives us the instance SwiftUI created earlier.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

swiftui

uikit

swift

ios

How to use SceneDelegate in SwiftUI

Learn how to integrate SceneDelegate with a SwiftUI-based application.

17 Feb 2025 · 5 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum