SwiftUI实现UserProfiling未完成时禁止跳转ContentView的问题
问题描述
需求逻辑:
- 用户首次登录或未完成UserProfiling时,禁止跳转到ContentView
- 用户已完成UserProfiling时,自动跳转至ContentView
当前问题:完成UserProfiling后无法自动跳转,必须重启应用才能进入ContentView
相关代码
UserProfiling ViewModel
class UserProfiling: ObservableObject { @Published var selectedLanguages: [String] = [] @Published var isProfileCompleted: Bool = false private var db = Firestore.firestore() private var userId: String? init() { if let userId = Auth.auth().currentUser?.uid { self.userId = userId checkUserProfiling() } } func checkUserProfiling() -> Bool { guard let userId = Auth.auth().currentUser?.uid else { return false } db.collection("users").document(userId).getDocument { snapshot, error in if let error = error { print("Error getting user profiling: \(error.localizedDescription)") } else if let snapshot = snapshot, snapshot.exists { let data = snapshot.data() if let isProfileCompleted = data?["isProfileCompleted"] as? Bool { self.isProfileCompleted = isProfileCompleted } } } return isProfileCompleted } func saveUserProfiling(completion: @escaping (Bool) -> Void) { print(selectedLanguages) guard let uid = Auth.auth().currentUser?.uid else { completion(false) return } let documentRef = db.collection("users").document(uid) documentRef.setData([ "selectedLanguages": selectedLanguages, "isProfileCompleted": true ], merge: true) { error in if let error = error { print("Error saving user profiling data to firestore :\(error.localizedDescription)") completion(false) } else { print("User profiling data saved to firestore successfully.") DispatchQueue.main.async { self.isProfileCompleted = true } completion(true) } } } }
MoovieApp.swift
// // MoovieApp.swift // Moovie // // Created by Putut Yusri Bahtiar on 26/03/23. // import SwiftUI import FirebaseCore @main struct MoovieApp: App { @StateObject var sessionAuth = SessionAuth() @StateObject var userProfiling = UserProfiling() init() { FirebaseApp.configure() } var body: some Scene { WindowGroup { if sessionAuth.isLoggedIn { if userProfiling.isProfileCompleted { ContentView() .environmentObject(sessionAuth) .environmentObject(userProfiling) } else { UserProfilingView() .environmentObject(sessionAuth) .environmentObject(userProfiling) } } else { LoginView() .environmentObject(sessionAuth) } } } }
问题分析与修复方案
核心问题
checkUserProfiling异步逻辑错误:该方法返回值时,Firestore的异步请求还未完成,返回的是初始默认值false。后续异步回调更新isProfileCompleted时,初始视图已经渲染完成,不会自动刷新。- 登录状态变更未触发Profile检查:
UserProfiling的checkUserProfiling仅在初始化时调用一次,若用户是在App启动后登录(从LoginView跳转),不会重新检查Profile状态。
修复步骤
1. 修正checkUserProfiling方法
去掉无效的返回值,专注于异步更新isProfileCompleted:
func checkUserProfiling() { guard let userId = Auth.auth().currentUser?.uid else { self.isProfileCompleted = false return } db.collection("users").document(userId).getDocument { snapshot, error in if let error = error { print("Error getting user profiling: \(error.localizedDescription)") self.isProfileCompleted = false } else if let snapshot = snapshot, snapshot.exists { let data = snapshot.data() self.isProfileCompleted = data?["isProfileCompleted"] as? Bool ?? false } else { self.isProfileCompleted = false } } }
2. 监听登录状态,触发Profile检查
在MoovieApp中,当sessionAuth.isLoggedIn变为true时,重新调用checkUserProfiling:
@main struct MoovieApp: App { @StateObject var sessionAuth = SessionAuth() @StateObject var userProfiling = UserProfiling() init() { FirebaseApp.configure() } var body: some Scene { WindowGroup { if sessionAuth.isLoggedIn { // 登录状态变更时重新检查Profile let _ = sessionAuth.$isLoggedIn .sink { isLoggedIn in if isLoggedIn { userProfiling.checkUserProfiling() } } if userProfiling.isProfileCompleted { ContentView() .environmentObject(sessionAuth) .environmentObject(userProfiling) } else { UserProfilingView() .environmentObject(sessionAuth) .environmentObject(userProfiling) } } else { LoginView() .environmentObject(sessionAuth) } } } }
3. 保留现有saveUserProfiling逻辑
saveUserProfiling中已经在主线程更新isProfileCompleted,这部分是正确的,@Published属性变更会自动触发视图刷新,完成Profile后无需额外操作即可跳转。
内容的提问来源于stack exchange,提问作者Putyourz
相关产品推荐
相关产品推荐

