Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pass data from UIKit to SwiftUI (container UIHostingController)

Tags:

swift

swiftui

How to pass data between UIViewController and struct ContentView?

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

like image 826
Yug Normand Ngangue Avatar asked May 11 '20 15:05

Yug Normand Ngangue


People also ask

How do I pass data between SwiftUI and UIKit?

First, use binding to your input view. And for action use closure to get action from SwiftUI to UIKit. Here is a possible solution. override func viewDidLoad() { super.

Can you mix UIKit and SwiftUI?

The UIViewRepresentable protocol allows you to adapt to the mechanism of SwiftUI declarative views and creates a bridge between UIKit and SwiftUI. Whether it's a custom UIView created by yourself or a UIView provided by Apple that isn't available in UIKit yet: you can make them available in SwiftUI.

What is a Uihostingcontroller?

A UIKit view controller that manages a SwiftUI view hierarchy.


3 Answers

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
like image 51
Adrian Avatar answered Oct 19 '22 19:10

Adrian


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)));
    }
}
like image 6
James Avatar answered Oct 19 '22 17:10

James


  1. Add class myclassname: ObservableObject

  2. In the class create a variable with @Published var myvar and add:

    init(myvar: type) {
      self.myvar = myvar
    }
    
  3. In UIViewController add:

    private var model = myclassname(myvar: XXX)`
    

    and in viewWillAppear add:

    let vc = myclassname(myvar: myvar)
    let childView = UIHostingController(rootView: ContentView(model: vc))
    
  4. In the struct add:

    @ObservedObject var model: myclassname
    
like image 3
Yug Normand Ngangue Avatar answered Oct 19 '22 18:10

Yug Normand Ngangue