Identifiable/Decodable协议User结构体如何添加followers/following属性
Firebase 适配 Decodable 协议的 User 模型添加 followers/following 属性实现
你可以根据 Firestore 中用户数据的实际存储结构,选择对应实现方式:
方案1:保留嵌套统计结构(匹配当前编写的 UserStats 逻辑)
如果你的 Firestore 用户文档将粉丝、关注计数存在 stats 嵌套字段下,存储结构参考:
users/{documentId} ├─ username: 字符串 ├─ fullname: 字符串 ├─ profileImageUrl: 字符串 ├─ email: 字符串 └─ stats: { followers: 数值型, following: 数值型 }
现有模型逻辑基本可用,只需要补全缺省值兜底,避免老数据缺字段时解码失败,修正后的完整代码:
import Firebase import FirebaseFirestoreSwift struct User: Identifiable, Decodable { // 自动映射 Firestore 文档ID,无需在文档中额外存储uid字段,避免数据冗余 @DocumentID var id: String? let username: String let fullname: String let profileImageUrl: String let email: String let stats: UserStats // 判断当前用户实例是否为已登录账号 var isCurrentUser: Bool { Auth.auth().currentUser?.uid == id } // 补全解码兜底,避免stats字段缺失时解码失败 enum CodingKeys: String, CodingKey { case id, username, fullname, profileImageUrl, email, stats } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decodeIfPresent(DocumentID<String>.self, forKey: .id)?.wrappedValue self.username = try container.decode(String.self, forKey: .username) self.fullname = try container.decode(String.self, forKey: .fullname) self.profileImageUrl = try container.decode(String.self, forKey: .profileImageUrl) self.email = try container.decode(String.self, forKey: .email) self.stats = try container.decodeIfPresent(UserStats.self, forKey: .stats) ?? UserStats(followers: 0, following: 0) } } struct UserStats: Decodable { let followers: Int let following: Int // 补全字段缺省兜底 enum CodingKeys: String, CodingKey { case followers, following } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.followers = try container.decodeIfPresent(Int.self, forKey: .followers) ?? 0 self.following = try container.decodeIfPresent(Int.self, forKey: .following) ?? 0 } // 默认兜底用初始化方法 init(followers: Int, following: Int) { self.followers = followers self.following = following } }
方案2:直接在 User 根节点添加统计属性
如果 Firestore 没有嵌套 stats 字段,直接把 followers、following 存在用户文档根目录,直接在 User 结构体里声明对应属性即可,不需要单独拆分 UserStats:
import Firebase import FirebaseFirestoreSwift struct User: Identifiable, Decodable { @DocumentID var id: String? let username: String let fullname: String let profileImageUrl: String let email: String let followers: Int let following: Int var isCurrentUser: Bool { Auth.auth().currentUser?.uid == id } // 补全缺省值兜底,避免老数据缺字段解码失败 enum CodingKeys: String, CodingKey { case id, username, fullname, profileImageUrl, email, followers, following } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decodeIfPresent(DocumentID<String>.self, forKey: .id)?.wrappedValue self.username = try container.decode(String.self, forKey: .username) self.fullname = try container.decode(String.self, forKey: .fullname) self.profileImageUrl = try container.decode(String.self, forKey: .profileImageUrl) self.email = try container.decode(String.self, forKey: .email) self.followers = try container.decodeIfPresent(Int.self, forKey: .followers) ?? 0 self.following = try container.decodeIfPresent(Int.self, forKey: .following) ?? 0 } }
踩坑提示
@DocumentID修饰的属性必须声明为可选类型,否则会出现类型不匹配的解码错误- 模型属性名必须和 Firestore 存储的字段名完全一致,大小写、拼写偏差都会导致解码失败,需要自定义映射关系可以通过
CodingKeys调整 - 如果后续要存储粉丝/关注的用户ID列表而非计数,直接把对应字段类型改为
[String]即可,解码逻辑和普通字段一致
内容的提问来源于stack exchange,提问作者whoolee
相关产品推荐
相关产品推荐

