使用Codable从FireStore读取自定义数据类型时遇数据丢失问题
问题描述
我正在用Codable从Firebase FireStore读取自定义数据类型(map),这是低开销的数据检索方式。只用GBplayer结构体时脚本正常运行,能在SwiftUI视图里获取完整列表,但添加shotAverages结构体后,Firestore文档里包含该字段的玩家会从列表中消失,无法被检索到。
数据模型
struct GBplayer: Identifiable, Codable { @DocumentID var id: String? = UUID().uuidString var name: String var status: String var age: String var height: String var college: String var team: String var position: String var shootingAverages: shotAverages? } struct shotAverages: Identifiable, Codable { @DocumentID var id: String? = UUID().uuidString var aveTWOperc: Double var aveTHREEperc: Double var aveFTperc: Double var aveeFGperc: Double }
数据视图模型
class GBplayerModel: ObservableObject { @Published var playerList = [GBplayer]() // 获取数据库引用 let db = Firestore.firestore() func getGBplayers() { db.collection("GBplayers").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { print("没有找到文档") return } self.playerList = documents.compactMap { (queryDocumentSnapshot) -> GBplayer? in return try? queryDocumentSnapshot.data(as: GBplayer.self) } } } }
Firestore数据结构参考截图:
问题排查与解决
核心原因
shotAverages结构体中的@DocumentID注解是问题根源。@DocumentID是Firebase用来映射独立文档ID的属性包装器,但shotAverages只是Firestore文档里的嵌套map字段,并不是独立文档,不存在对应的文档ID。Codable解析时找不到这个ID字段,会导致整个GBplayer对象解析失败,被compactMap过滤掉,所以带该字段的玩家从列表中消失。
修复方案
- 移除
shotAverages里的@DocumentID属性,嵌套map不需要文档ID; - 遵循Swift命名规范,结构体首字母大写(改为
ShotAverages),避免风格不一致引发潜在问题。
修改后的代码:
// 修正后的嵌套结构体 struct ShotAverages: Codable { var aveTWOperc: Double var aveTHREEperc: Double var aveFTperc: Double var aveeFGperc: Double } // 更新GBplayer中的字段类型 struct GBplayer: Identifiable, Codable { @DocumentID var id: String? = UUID().uuidString var name: String var status: String var age: String var height: String var college: String var team: String var position: String var shootingAverages: ShotAverages? }
额外注意事项
- 确认Firestore中嵌套map的字段名和结构体属性名完全匹配(大小写敏感),比如截图中的
aveeFGperc要和代码里的属性名一致; - 保持
shootingAverages为可选类型是正确的,这样没有该字段的文档也能正常解析。
内容的提问来源于stack exchange,提问作者Adam Sewell
相关产品推荐
相关产品推荐

