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

Swift中Firestore getDocuments查询快照内无法给变量赋值如何解决?

核心原因

getDocuments 是异步执行的接口,你写的return语句会在网络请求返回、回调触发前就执行完毕,所以拿到的永远是retVal的初始值。

解决方案

方案1:使用完成回调(全系统版本兼容)

把需要拿到判断结果后执行的逻辑,放到回调闭包中执行,示例代码如下:
首先封装判断逻辑的方法:

func checkUsernameUnique(username: String, completion: @escaping (Bool, Error?) -> Void) {
    Firestore.firestore().collection("users")
        .whereField("username", isEqualTo: username)
        .getDocuments { querySnapshot, error in
            if let error = error {
                print(error.localizedDescription)
                completion(false, error)
                return
            }
            let isUnique = querySnapshot?.isEmpty ?? false
            print(isUnique ? "QuerySnapshot is empty, this is unique" : "There's a bloody username in here, get a new one")
            completion(isUnique, nil)
        }
}

调用方法示例:

guard let inputUsername = usernameTextField.text, !inputUsername.isEmpty else {
    // 处理输入为空的异常逻辑
    return
}
checkUsernameUnique(username: inputUsername) { [weak self] isUnique, error in
    guard let self = self else { return }
    // 所有需要用到isUnique结果的逻辑都写在这个闭包里
    if let error = error {
        // 弹出网络/服务错误提示
        return
    }
    if isUnique {
        // 用户名唯一,执行后续注册、提交等逻辑
    } else {
        // 提示用户用户名已存在,要求更换
    }
}

方案2:使用async/await(适配iOS 15+)

如果你的App最低支持版本在iOS 15及以上,可以用Swift Concurrency的异步写法,避免闭包嵌套,代码更简洁:
封装方法:

func checkUsernameUnique(username: String) async throws -> Bool {
    let snapshot = try await Firestore.firestore().collection("users")
        .whereField("username", isEqualTo: username)
        .getDocuments()
    return snapshot.isEmpty
}

调用示例:

Task {
    guard let inputUsername = usernameTextField.text, !inputUsername.isEmpty else {
        return
    }
    do {
        let isUnique = try await checkUsernameUnique(username: inputUsername)
        // 拿到结果后执行后续逻辑
        if isUnique {
            // 用户名可用
        } else {
            // 用户名重复
        }
    } catch {
        // 处理请求错误
        print(error.localizedDescription)
    }
}

注意事项

不要使用DispatchSemaphore等方式阻塞主线程等待异步结果,会导致UI无响应,严重时会被系统直接杀死应用,所有依赖异步结果的逻辑都应该放到异步回调的上下文中执行


内容的提问来源于stack exchange,提问作者EAO123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:18:03