'pass data from UIKit to SwiftUI (container UIHostingController)

How to pass data between UIViewController and struct ContentView?

I tried with ObservableObject but I can't get the data up to date.



Solution 1:[1]

  1. class myclassname: ObservableObject

  2. in the class create variable with @Published var myvar and create init(myvar: type) { self.myvar = myvar }

  3. in my UIViewController create private var model = myclassname(myvar: XXX) and in viewWillAppear------>let vc = myclassname(myvar: myvar) let childView = UIHostingController(rootView: ContentView(model: vc))

  4. in my struct ---> @ObservedObject var model: myclassname

Solution 2:[2]

To pass data from a UIViewController to an SwiftUI-Struct inside an UIHostingController you can attach an environmentObject to the SwiftUI rootView:

let vc = UIHostingController(rootView: YourContentView().environmentObject(yourEnvironmentObject))

Of course you'll need to create an ObservableObject and add it to your SwiftUI-Struct.

Create the ObservableObject:

class TypeOfEnvironmentObject: ObservableObject {
    @Published var data = "myData"
}

Add it to your struct:

@EnvironmentObject var yourEnvironmentObject: TypeOfEnvironmentObject

Solution 3:[3]

I found the existing answers confusing/incomplete, perhaps something changed around generic inference in Swift 5.3 etc. While you can add an environment object to the UIHostingController's view this seems to conflict with the types (i.e. the generic parameter to UIHostingController needs a concrete type). Adding AnyView resolves this:

import UIKit
import SwiftUI

struct TutorialView: View {
    
    @EnvironmentObject private var integration: TutorialIntegrationService
    
    var body: some View {
        Text("Hi").navigationBarTitle("test: \(integration.id)")
    }
}

class TutorialIntegrationService: ObservableObject {
    @Published var id: Int = 0
}

class TutorialViewController: UIHostingController<AnyView> {
    
    let integration = TutorialIntegrationService()
    
    required init?(coder: NSCoder) {
        super.init(coder: coder,rootView: AnyView(TutorialView().environmentObject(integration)));
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 James