loading...

Working with your UIViewController and SwiftUI

kevinmaarek profile image Maarek ・1 min read

So you started playing with SwiftUI, and you enjoyed it ? Well, me too! The second it came out, I started to imagine all the use cases I'll enjoy implementing my views with this framework.

If like, me you wonder how to use your fresh made SwiftUI views along with your good old UIViewController, this is for you!

To work with you ViewControllers Apple added this magic protocol : UIViewControllerRepresentable.
How it works ?
Well, you have two options (at the moment) :

Make your UIViewController Representable.

Just conform to UIViewControllerRepresentable. Doing so, you'll have to make you UIViewController final, preventing your class from being inherited or being overridden.
This is what it would look like :

extension ViewController: UIViewControllerRepresentable {
    public typealias UIViewControllerType = ViewController

    public func makeUIViewController(context: UIViewControllerRepresentableContext<ViewController>) -> ViewController {
        return ViewController()
    }

    public func updateUIViewController(_ uiViewController: ViewController, context: UIViewControllerRepresentableContext<ViewController>) {
        //
    }
}

Using a wrapper.

The other option is to make a sort of ViewControllerWrapper. This is the one I chose to adopt as it does not require the class being final.
Just create a Struct that conforms to UIViewControllerRepresentable, and return an initialized ViewController in the makeUIViewController method :

struct ViewControllerWrapper: UIViewControllerRepresentable {

    typealias UIViewControllerType = ViewController


    func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerWrapper>) -> ViewControllerWrapper.UIViewControllerType {
        return ViewController()
    }

    func updateUIViewController(_ uiViewController: ViewControllerWrapper.UIViewControllerType, context: UIViewControllerRepresentableContext<ViewControllerWrapper>) {
        //
    }
}

And simply call it in your SwiftUI views like so :

struct MyView : View {
    var body: some View {
        ViewControllerWrapper()
    }
}

Using a "wrapper" solution would allow to easily add any parameter to initialize your ViewController.

There you are.
Hope this will help!

Happy coding :)

Posted on by:

kevinmaarek profile

Maarek

@kevinmaarek

Swift developer 👨🏻‍💻 Space geek 🚀 Photography nerd 📷

Discussion

pic
Editor guide
 

Almost there with my test, but the original ViewController lacks something, as the compiler cries:

Protocol 'View' requirement '_makeView(view:inputs:)' cannot be satisfied by a non-final class ('ViewController') because it uses 'Self' in a non-parameter, non-result type position

Can you point me to the "non-final class" fundamentals?

Thanks for the pathway!

PS: Adding "final" to the class declaration compiles, but no view is rendered

 

Can you provide some of your SwiftUI code ?

 

Thanks... but... solved!

Thing is that you can also do:


 func makeUIViewController(context: UIViewControllerRepresentableContext<MyView>) -> ViewController {


        return UIStoryboard(name: "MyViewControllerStoryboard", bundle: nil).instantiateViewController(identifier: String(describing: ViewController.self)) as! ViewController

    }

Cheers!

 

I have a project of pattern lock built in UIKit and I want to import it into my SwiftUI project as a View in full page. So my question is how will I get the UI as it is build in Storyboard?
Is it possible to achieve that using UIViewController ?

Github Repo Pattern Lock => github.com/Tinghui/HUIPatternLockV...

Thank You.

 

I'm guessing the same is true of NSViewControllerRepresentable?

 

Exactly!