Swift调用fetchCurrentUser时self未初始化报错,如何用Firebase初始化用户?
问题解答:初始化时调用Firestore方法报错及替代方案
错误原因解析
你遇到的错误和user是可选类型无关,问题出在非可选属性isLogOut还未完成初始化时,就调用了需要访问self的实例方法fetchCurrentUser。Swift的初始化规则明确要求:必须给所有存储属性(无论可选与否)完成赋值后,才能使用self(包括调用实例方法、访问实例属性)。你的init方法中先调用了fetchCurrentUser,此时isLogOut还未被赋值,因此编译器报错。
快速修复方案
调整init内的代码顺序,先给isLogOut赋值,再调用fetchCurrentUser即可解决:
init() { isLogOut = FirebaseManager.shared.auth.currentUser?.uid == nil fetchCurrentUser() // 所有存储属性已初始化,可安全调用方法 }
其他Firebase初始化user的方法
1. 使用Async/Await简化异步逻辑
Firebase已支持async/await语法,代码更简洁易读,可在init中通过Task调用:
func fetchCurrentUser() async { guard let uid = FirebaseManager.shared.auth.currentUser?.uid else { return } do { let document = try await FirebaseManager.shared.firestore.collection("users").document(uid).getDocument() if let data = document.data() { self.user = User( uid: data["uid"] as? String ?? "", email: data["email"] as? String ?? "", profilePicURL: data["url"] as? URL ?? URL(string: "")! ) } } catch { print("获取用户数据失败:\(error)") } } // 初始化方法中调用 init() { isLogOut = FirebaseManager.shared.auth.currentUser?.uid == nil Task { await fetchCurrentUser() } }
2. 监听Auth状态自动同步用户数据
不再在init中主动调用,而是监听Firebase Auth的用户状态变化,登录/登出时自动触发数据获取,适合实时同步场景:
class UserViewModel: ObservableObject { @Published var user: User? @Published var isLogOut: Bool private var authStateListener: AuthStateDidChangeListenerHandle? init() { isLogOut = FirebaseManager.shared.auth.currentUser?.uid == nil setupAuthStateListener() } private func setupAuthStateListener() { authStateListener = FirebaseManager.shared.auth.addStateDidChangeListener { [weak self] auth, user in guard let self = self else { return } self.isLogOut = user == nil if let uid = user?.uid { self.fetchCurrentUser(uid: uid) } else { self.user = nil } } } private func fetchCurrentUser(uid: String) { FirebaseManager.shared.firestore.collection("users").document(uid).getDocument { snapshot, err in guard let data = snapshot?.data() else {return} self.user = User( uid: data["uid"] as? String ?? "", email: data["email"] as? String ?? "", profilePicURL: data["url"] as? URL ?? URL(string: "")! ) } } // ViewModel销毁时移除监听,避免内存泄漏 deinit { if let listener = authStateListener { FirebaseManager.shared.auth.removeStateDidChangeListener(listener) } } }
3. Lazy初始化(不推荐UI场景)
将user声明为lazy属性,结合信号量阻塞线程完成异步加载,但会阻塞初始化线程,仅适合后台场景:
class UserViewModel: ObservableObject { @Published private(set) lazy var user: User? = { guard let uid = FirebaseManager.shared.auth.currentUser?.uid else { return nil } var tempUser: User? let semaphore = DispatchSemaphore(value: 0) FirebaseManager.shared.firestore.collection("users").document(uid).getDocument { snapshot, err in if let data = snapshot?.data() { tempUser = User( uid: data["uid"] as? String ?? "", email: data["email"] as? String ?? "", profilePicURL: data["url"] as? URL ?? URL(string: "")! ) } semaphore.signal() } semaphore.wait() return tempUser }() @Published var isLogOut: Bool init() { isLogOut = FirebaseManager.shared.auth.currentUser?.uid == nil } }
内容的提问来源于stack exchange,提问作者Mikael Mikaelian
相关产品推荐
相关产品推荐

