简体   繁体   中英

SwiftUI ObservedObject not updating view after successful login

To show my the content from my root view after successful login, I tried with ObservedObject , and with EnvironmentObject , to no avail.

Eg as follows:

struct RootView: View {

    @EnvironmentObject var loginManager: LoginManager

    var body: some View {
        Group {
            if loginManager.isLoggedIn {
                SegmentedView()
            }
            else {
                WelcomeView()
            }
        }
    }
}

class LoginManager: ObservableObject {
    
    static let shared = LoginManager()
    var cancellable = Set<AnyCancellable>()
    @Published var isLoggedIn = false

    ...
    
    func login(...) {
        ...
        // on success
        self.isLoggedIn = true
    }

The LoginManager is retained in the SceneDelegate and put into the environment:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    var loginManager = LoginManager.shared
    ...

    // the view passed to window.rootUiewController via UIHostingController
    let contentView = RootView().environmentObject(loginManager)

After logging in, it goes right back to my WelcomeView . What am I missing?

EDIT

Here is a new aspect. I have a view model for the LoginView to manage the data in date fields. When the login button is pressed, I call a login() method in this view model.

I need to two .sink callbacks in the view model, because I have to dismiss the loading indicator by setting a loading flag to false.

So I cannot call self.isLoggedIn = true directly because I am in the view model, not the LoginManager . Instead I call

self.loginManager.isLoggedIn = true 

and I suspect that this line is not working.

The connection between view model and login manager is done like this

@ObservedObject var loginManager = LoginManager.shared

However, after shifting this to the LoginManager , I am indeed calling self.isLoggedIn from there. It is still not working.

I have two theses:

  1. It could be that the view is not set up correctly with Group etc. I also tried to use @ViewBuilder etc, no difference.

  2. It could be that somehow there are two instances of LoginManager , or the RootView somehow get's reinitialised with a new instance where isLoggedIn is false. But I have been creating Swift singletons like this for ages:

    static let shared = LoginManager()

and never had any problems.

As mentioned in the comments, there is another error I encountered when switching all to @EnvironmentObject :

Fatal error: No ObservableObject of type LoginManager found. A View.environmentObject(_:) for LoginManager may be missing as an ancestor of this view.: file SwiftUI, line 0

I think I got the error.

I assumed .sink(receiveCompletion: always has an error because the template to which I was referring to it. But the completion block is called no matter what.

Unfortunately, if you insert a parameter error in it will never be nil but contain something like

Combine.Subscribers.Completion<module.CustomError>.finished

So I guess, you are not supposed to check for errors there again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM