You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:30:44