Using a SwiftUI View in a UIKit App

Using a SwiftUI View in a UIKit App

By the end of this tutorial, you will be able to programmatically integrate a SwiftUI View into a UIKit app.

The SwiftUI framework was unveiled in 2019 and in just a few years has proven to be impactful in the developer community. But it is also true that UIKit has been around since 2008! Especially if you have been a developer for a few years you will have Apps developed using UIKit. Why not use all that SwiftUI has to offer to give your apps a makeover?

Given the benefits of using SwiftUI for future development, it will be a common requirement to integrate the new SwiftUI app functionality with the existing project codebase. Fortunately, this integration can be achieved easily using UIHostingController. Let's have a look.

UIHostingController

The hosting controller is compatible with UIKit since it is a subclass of UIViewController. The purpose of the UIHostingController is to enclose a SwiftUI view so that it can be integrated into an existing UIKit based project.

Apple Developer Documentation

Check Apple's documentation about UIHostingController if you want to know more.

Using a HostingViewController, a SwiftUI view can be treated either as an entire scene (occupying the full screen) or as an individual component within an existing UIKit scene.

In this tutorial, we will walk through how to integrate a SwiftUI view by treating it as an entire scene.

Starting point and goal

Our starting point is an essential UIKit based app using the Storyboard. The main ViewController contains a simple UIImage a UILabel and a UIButton. The only component we are going to really use in this tutorial is the filled UIButton titled “Go to SwiftUI View”.

UIKit based app using a Storyboard

The goal is to navigate from the ViewController to an animated View developed in SwiftUI when tapping on the UIButton just described.

SwiftUI animated View

In the animated image below you can see what we will create together at the end.

Tutorial final result

Create the integration programmatically

Let’s move the ViewController.swift file controlling the button we are interested in.

1. First of all, if you are using a Storyboard for your app, create a @IBAction for your UIButton.

class ViewController: UIViewController {
    
    // 1. Create the IBAction outlet
    @IBAction func goToSwiftUIView(_ sender: Any) {
        // add action
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

2. Create a UIHostingController named swiftUIController using the SwiftUIView() as a root view so that it can be integrated into our UIKit based project.

class ViewController: UIViewController {

    // 2. Create a UIHostingController
    let swiftUIController = UIHostingController(rootView: SwiftUIView())
    
    // 1. Create the IBAction outlet
    @IBAction func goToSwiftUIView(_ sender: Any) {
        // add action
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

3. Now that we have a hosting controller, we can use it as we would for any other view controller. In this example, we are pushing the swiftUIController using the navigationController that embeds the ViewController.

class ViewController: UIViewController {

    // 2. Create a UIHostingController
    let swiftUIController = UIHostingController(rootView: SwiftUIView())
    
    // 1. Create the IBAction outlet
    @IBAction func goToSwiftUIView(_ sender: Any) {
        // 3. Push the UIHostingController
        navigationController?.pushViewController(swiftUIController, animated: true)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

Create the integration using the Storyboard and a Segue Outlet

1. Add a UIHostingController in the Storyboard
Open the Library by clicking on the + button in Xcode’s top right corner. Search for UIHostingController and drag and drop it to the Storyboard.

Add a UIHostingController in the Storyboard

2. Create a Segue in the Storyboard
To create a Segue control-drag (hold down the ctrl key and drag the element) from the UIButton in the main ViewController to the UIHostingController we have just added.

Create a Segue in the Storyboard

3. Create a Segue Outlet
Using the Assistant editor, which allows you to see the Storyboard and code at the same time, we create a Segue Outlet by control-dragging from the Storyboard arrow (connecting the two ViewControllers) to the ViewController class. We have just created a @IBSegueAction and we named it segueToSwiftUIView.

Create a Segue Outlet

4. Implement the @IBSegueAction
Move to the ViewController.swift and let’s modify the placeholder Xcode added for us with the creation of the @IBSegueAction.
We are going to return a UIHostingController that uses the SwiftUIView as a root view so that it can be integrated into our UIKit based project. coder is an abstract class that serves as the basis for objects that enable archiving and distribution of other objects.

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    // 3. Create a Segue Outlet
    @IBSegueAction func segueToSwiftUIView(_ coder: NSCoder) -> UIViewController? {
        // 4. Implement the @IBSegueAction 
        return UIHostingController(coder: coder, rootView: SwiftUIView())
    }
}

Your UIKit based project is now hosting an animated SwiftUI View! Creating an animation is just one of the possible examples where it can be convenient to use SwiftUI instead of other frameworks (like UIKit). You now have a new ace up your sleeve to speed up your legacy app development process.

Wrapping up

We have explored two different ways to integrate our SwiftUI views into a UIKit-based app. Specifically, we used our SwiftUI views as entire scenes in our app.

As next steps you could explore: