【问题标题】:Programatic navigation on authentication SwiftUI with Publishers使用 Publishers 进行身份验证 SwiftUI 的编程导航
【发布时间】:2022-01-22 08:11:18
【问题描述】:

我在 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
        }
    }
}

【问题讨论】:

  • 感谢您提出这个问题。我正在尝试做类似的事情。你能告诉我你发布的变量有什么区别:session: User?profile: UserProfile? 声明吗?我的意思是,你在每个中存储什么?

标签: firebase google-cloud-firestore swiftui navigation


【解决方案1】:

我看到你正在使用 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()
            }
        }
    }
}

【讨论】:

  • 不应该是ObservedObject而不是EnvironmentObject吗? (hackingwithswift.com/quick-start/swiftui/…)
  • @Zonker.in.Geneva @ObservedObject 用于可能属于多个视图的复杂属性。大多数时候你使用引用类型你应该使用@ObservedObject。而@EnvironmentObject 用于在应用程序的其他位置创建的属性,例如共享数据。在这种情况下,所有应用程序模块都将监视状态的身份验证。
【解决方案2】:

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

【讨论】:

【解决方案3】:

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

在你的 MyApp 中,做

@StateObject var session = SessionStore()

在其他人看来,做

@EnvironmentObject var session: SessionStore

而且,您忘记将 environmentObject 传递给您的 SignInScreen

.environmentObject(session)

【讨论】:

  • 可以将第一行和第三行代码合并,直接写.environmentObject(SessionStore())
猜你喜欢
  • 2019-11-26
  • 2020-03-16
  • 2011-06-27
  • 2017-09-11
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
相关资源
最近更新 更多