Swift Codable解码Firebase字典为模型数组报错修复
问题原因
Firebase Realtime Database 返回的列表类数据默认是以自动生成的push ID为key、条目内容为value的字典结构,而非数组。你当前模型里把usedBy声明为[PromoCodeUsed]?数组类型,和返回的字典结构不匹配,所以触发类型不匹配的解码错误。
解决方案
两种实现方式二选一即可,原有数据拉取逻辑不需要改动:
方案1:自定义解码逻辑自动转数组
直接修改PromoCode结构体的解码实现,自动把字典值映射为数组,业务层调用时无感知:
struct PromoCode: Codable { var active: Int var amount: Int? var code: String var percent: Int? var owner: Int? var usedBy: [PromoCodeUsed]? enum CodingKeys: String, CodingKey { case active, amount, code, percent, owner, usedBy } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) active = try container.decode(Int.self, forKey: .active) amount = try container.decodeIfPresent(Int.self, forKey: .amount) code = try container.decode(String.self, forKey: .code) percent = try container.decodeIfPresent(Int.self, forKey: .percent) owner = try container.decodeIfPresent(Int.self, forKey: .owner) // 先按字典结构解码,再提取value转为数组 let usedByDict = try container.decodeIfPresent([String: PromoCodeUsed].self, forKey: .usedBy) usedBy = usedByDict?.map { $0.value } // 如果需要按时间排序可以加排序逻辑:usedBy = usedByDict?.values.sorted { $0.date < $1.date } } // 如果后续需要把模型编码回传Firebase,补全encode方法即可 // func encode(to encoder: Encoder) throws { ... } } struct PromoCodeUsed: Codable { var amount: Int var date: String var paid: Bool var userid: Int }
如果需要保留Firebase生成的push ID(比如-N5lHtnKtAiBWrQMxW0a这类key),可以给PromoCodeUsed新增id字段,解码时把字典key赋值给对应id即可。
方案2:模型先匹配字典结构,使用时再转数组
不想写自定义解码逻辑的话,可以先把usedBy声明为字典类型,业务层使用时再转为数组:
struct PromoCode: Codable { var active: Int var amount: Int? var code: String var percent: Int? var owner: Int? // 直接匹配原始返回的字典结构 var usedBy: [String: PromoCodeUsed]? } struct PromoCodeUsed: Codable { var amount: Int var date: String var paid: Bool var userid: Int }
业务层使用时转换:
// 取所有使用记录,需要排序自行加排序逻辑 let usedRecordList = decoded.usedBy?.map { $0.value }
注意:字典的values默认是无序的,如果需要和Firebase控制台展示的顺序一致,转数组时需要按业务字段(比如date)做排序。
内容的提问来源于stack exchange,提问作者tHatpart
相关产品推荐
相关产品推荐

