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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:06:18