Rs Graphics
Rs Graphics

Reputation: 193

Call a function from SwiftUI in UIHostingController

I have a swift UIHostingController which renders a SwiftUI. I call a function in view did appear which builds fine but doesn't create the intended output.

class LoginView: UIHostingController<LoginViewComponent> {
    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: LoginViewComponent())
    }

    override func viewDidAppear(_ animated: Bool) {
        sessionHandler()
    }

    func sessionHandler(){
        let user = User()
        if user.isLoggedIn(){
            view.isUserInteractionEnabled = false
            print("Authenticating Session")
            self.rootView.loginState(state: "success")
        }else{
            view.isUserInteractionEnabled = true
            print("Needs Logging in")
        }
    }

}

The function ("loginState(state: "success")") works when called within the SwiftUI view class, however when called from the hosting controller it doesn't work.

Any help would be greatly appreciated.

Upvotes: 6

Views: 2830

Answers (1)

Asperi
Asperi

Reputation: 257663

SwiftUI is reactive state-base machine, actually, and all views are struct values, so you need to change concept, instead of imperatively send messages specify state dependency and reactions on those states...

Thus, keeping your custom-host-controller it could be set up like the following

import SwiftUI
import UIKit
import Combine

// model that keeps login state
class LoginState: ObservableObject {
    @Published var state: String = ""
}

struct LoginViewComponent: View {
    @EnvironmentObject var loginState: LoginState // state to be observed

    ...
   // somewhere in body you use loginState.state
   // and view will be refreshed depending on state changes
}

class LoginView: UIHostingController<AnyView> {
    let loginState = LoginState() // here it is created

    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: AnyView(LoginViewComponent().environmentObject(self.loginState))) // here the ref injected
    }

    override func viewDidAppear(_ animated: Bool) {
        sessionHandler()
    }

    func sessionHandler(){
        let user = User()
        if user.isLoggedIn(){
            view.isUserInteractionEnabled = false
            print("Authenticating Session")
            self.loginState.state = "success" // here state changed
        }else{
            view.isUserInteractionEnabled = true
            print("Needs Logging in")
        }
    }

}

Upvotes: 1

Related Questions