带有 Publishers 的身份验证 SwiftUI 的编程导航

Programatic navigation on authentication SwiftUI with Publishers

我在 SwitUI 应用程序中有此验证代码。 SessionStore 是一个可观察对象,它被注入到应用程序的主入口点。当标志成功时,然后导航到仪表板。 isLogin 变量改变但重定向没有发生。我不明白哪里做错了。

// 主视图

struct MyApp: App {
    @StateObject var session = SessionStore()
    
    init() {
        FirebaseApp.configure()
    }
    
    var body: some Scene {
        
        WindowGroup {
            SplashScreenView()
                .environmentObject(session)
        }
    }
}

// 重定向到登录或仪表板的启动画面视图

struct SplashScreenView: View {
    
    @StateObject var session = SessionStore()
    
    var body: some View {
        Group {
            if session.isLogedIn {
                DashboardScreen()
            } else  {
                SignInScreen()
            }
        }
    }
}

// 会话存储

class SessionStore: ObservableObject {
    @Published var session: User?
    @Published var profile: UserProfile?
    @Published var isLogedIn = false
    
    private var profileRepository = UserProfileRepository()
    
    func signUp(email: String, password: String, firstName: String, lastName: String, city: String, completion: @escaping (_ profile: UserProfile?, _ error: Error?) -> Void) {
        Auth.auth().createUser(withEmail: email, password: password) { (result, error) in
            if let error = error {
                print("Error signing up: \(error)")
                completion(nil, error)
                return
            }
            
            guard let user = result?.user else { return }
            print("User (user.uid) signed up.")
            
            let userProfile = UserProfile(uid: user.uid, firstName: firstName, lastName: lastName, city: city)
            self.profileRepository.createProfile(profile: userProfile) { (profile, error) in
                if let error = error {
                    print("Error while fetching the user profile: \(error)")
                    completion(nil, error)
                    return
                }
                self.profile = profile
                completion(profile, nil)
            }
        }
    }
    
    func signIn(email: String, password: String, completion: @escaping (_ profile: UserProfile?, _ error: Error?) -> Void) {
        Auth.auth().signIn(withEmail: email, password: password) { [self] (result, error) in
            if let error = error {
                print("Error signing in: \(error)")
                completion(nil, error)
                return
            }
            
            guard let user = result?.user else { return }
            print("User \(user.uid) signed in.")
            self.isLogedIn = true
            self.profileRepository.fetchProfile(userId: user.uid) { (profile, error) in
                if let error = error {
                    print("Error while fetching the user profile: \(error)")
                    completion(nil, error)
                    return
                }

                self.profile = profile
                completion(profile, nil)
            }
        }
    }
    
    func signOut() {
        do {
            try Auth.auth().signOut()
            self.session = nil
            self.profile = nil
        } catch let signOutError as NSError {
            print("Error signing out: \(signOutError)")
        }
    }
}

// 在我看来,我调用该方法并更新登录状态或注册。改变状态但不重定向

struct SignInScreen: View {
    @ObservedObject var sessionStore = SessionStore()
var body: some View {
Button(action:signIn, label: {
                        Text("Sign In")
                    })
 }

    func signIn() {
        loading = true
        error = false
        sessionStore.signIn(email: signInViewModel.emailAddress, password: signInViewModel.password) { (profile, error) in
          if let error = error {
            print("Error when signing up: \(error)")
            return
          }
            sessionStore.isLogedIn = true
        }
    }
}

您必须在 SplashScreenView 中使用 @EnvironmentObject var session: SessionStore 而不是 @StateObject。

目标是只有一个 SessionStore() 实例。 在这里,你重新定义了两次:@StateObject var session = SessionStore()

在您的 MyApp 中,执行

@StateObject var session = SessionStore()

在其他人看来,做

@EnvironmentObject var session: SessionStore

并且,您忘记将环境对象传递给 SignInScreen

.environmentObject(session)

我看到你在使用 firebase。如果您需要检查身份验证状态,这样做会很容易。

您的主要条目视图

struct MyApp: App {
    @StateObject var session = SessionStore()
    
    init() {
        FirebaseApp.configure()
    }
    
    var body: some Scene {
        
        WindowGroup {
            SplashScreenView()
                .environmentObject(session)
        }
    }
}

在您的会话存储中添加此代码以检查当前是否使用 FirebaseAuth 而不是手动登录。

class SessionStore: ObservableObject {
   
   // Previous code 
    var isSignIn: Bool {
        Auth.auth().currentUser?.uid != nil
    }

}

在启动画面中检查 isSignIn

struct SplashScreenView: View {
    
    @EnvironmentObject var session: SessionStore
    
    var body: some View {
        Group {
            if session.isSignIn {
                DashboardScreen()
            } else  {
                SignInScreen()
            }
        }
    }
}