DEV Community

Maarek
Maarek

Posted on

Working with your UIViewController and SwiftUI

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>) {
        //
    }
}

Enter fullscreen mode Exit fullscreen mode

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>) {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

And simply call it in your SwiftUI views like so :

struct MyView : View {
    var body: some View {
        ViewControllerWrapper()
    }
}
Enter fullscreen mode Exit fullscreen mode

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

There you are.
Hope this will help!

Happy coding :)

Top comments (6)

Collapse
 
jpelayo profile image
jpelayo • Edited

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

Collapse
 
kevinmaarek profile image
Maarek

Can you provide some of your SwiftUI code ?

Collapse
 
jpelayo profile image
jpelayo • Edited

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!

Collapse
 
utkarshshekhar profile image
Utkarsh Shekhar

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.

Collapse
 
steveblue profile image
Stephen Belovarich

I'm guessing the same is true of NSViewControllerRepresentable?

Collapse
 
kevinmaarek profile image
Maarek

Exactly!