Sharing variables between ViewController and SwiftUI

Viewed 2354

This is my first time working in Xcode and I am building an app using Storyboards/View Controllers. However, I have a page I want to display using SwiftUI, which I am doing through a host controller. I want to be able to assign a value to a variable in my ViewController code and then access this value in my swiftUI ContentView file. I feel like there should be a simple solution, but I can't seem to find a way to share data between the two. Thank you for any help.

2 Answers

Here is a simple method to see how to pass data to SwiftUI View from UIKit UIViewController. Here I'm passing a simple text setting it in the initializer of ContentView and presenting the UIHostingController on ViewController. Here is the code:

import UIKit
import SwiftUI
import PlaygroundSupport

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(action))
    }

    @objc func action() {
        let contentView = ContentView(text: "My Text")
        let viewController = UIHostingController(rootView: contentView)
        present(viewController, animated: true)
    }
}


struct ContentView: View {

    var text: String

    var body: some View {
        Text(text)
    }
}

PlaygroundPage.current.setLiveView(UINavigationController(rootViewController: ViewController()))
PlaygroundPage.current.needsIndefiniteExecution = true

You can copy/paste this code on your playground to see how it works.

Assuming you are using a UIHostingController and a story board segue, you can use the prepare for segue function to set a value in the rootView of the hosting view controller.

For example:

UIViewController

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "theSegue" {
            let dest = segue.destination as! TheHostingViewController
            dest.rootView.theString = "This is the String to pass"
        }
    }

}

UIHostingController

import UIKit
import SwiftUI

class TheHostingViewController: UIHostingController<TheSwiftUIView> {
    
    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder, rootView: TheSwiftUIView())
    }

    
    override func viewDidLoad() {
        super.viewDidLoad()

    }

}

SwiftUI view

import SwiftUI

struct TheSwiftUIView: View {
    
    var theString: String?

    var body: some View {
        Text(theString!)
    }
}

StoryBoard

Be sure to change the Class of the Hosting Controller to the name of your UIHostingController in interface builder (as shown in the image below).

Interface Builder

Related