Swift将Firestore请求从Completion改为Async/Await后解码报错求助
问题分析与解决办法
错误根源
你的Async/Await代码和原Completion回调代码有两个核心差异,导致了这个错误:
- 错误处理逻辑不同:原代码用
try?尝试解码,失败时直接return静默忽略错误;而新代码用try强制抛出解码错误,之前被隐藏的解码问题现在直接暴露了出来。 - 缺少文档存在性检查:原代码先判断
snapshot是否存在,不存在就直接返回;但新代码跳过了这个检查——如果指定uid的用户文档不存在,snapshot.data(as:)会因为没有可解码的数据,抛出"Cannot get keyed decoding container -- found null value instead"这个模糊错误。
修正后的代码
func fetchUser(withUid uid: String) async throws -> UserModel { let snapshot = try await Firestore.firestore().collection("users").document(uid).getDocument() // 先检查文档是否存在 guard snapshot.exists else { throw NSError(domain: "FirestoreError", code: -1, userInfo: [NSLocalizedDescriptionKey: "指定用户不存在"]) } // 尝试解码并处理解码错误 do { return try snapshot.data(as: UserModel.self) } catch { throw NSError(domain: "FirestoreError", code: -2, userInfo: [ NSLocalizedDescriptionKey: "用户数据解码失败", NSUnderlyingErrorKey: error ]) } }
关键修正点
- 新增
snapshot.exists检查,提前拦截文档不存在的情况,抛出明确的错误信息,避免后续解码时出现模糊的null错误 - 简化嵌套的
do-catch结构,让代码更易读 - 对解码错误进行包装,保留底层错误信息,方便上层调用时定位具体问题
额外说明
原Completion版本的静默失败逻辑在实际开发中其实存在隐患——调用者无法知道用户数据获取失败的原因。Async/Await版本通过抛出错误的方式,强制要求上层处理这些异常情况,反而更符合Swift的错误处理规范。
内容的提问来源于stack exchange,提问作者Mohamad Yahia
相关产品推荐
相关产品推荐

