Firebase匹配数据解码失败:JSON序列化后无法解析为FirestoreMatch
解码Firestore匹配数据时遇到类型不匹配错误
从Firebase获取匹配数据时,解码环节失败,相同逻辑在获取用户资料时可正常运行。
相关代码片段
fetchMatches函数
func fetchMatches(onCompletion: @escaping (Result<[MatchModel], DomainError>) -> ()){ db.collection("matches").whereField("usersMatched", arrayContains: userId!).getDocuments(completion: {doc, err in guard let documentSnapshot = doc, err == nil else{ onCompletion(.failure(.downloadError)) return } var matchList: [MatchModel] = [] var count = 0 let maxCount = documentSnapshot.documents.count var hasFailed = false for document in documentSnapshot.documents{ if hasFailed{ break } let decoder = JSONDecoder() var dict = document.data() for (key, value) in dict { if let value = value as? Timestamp { let formatter = DateFormatter() let newValue = value.dateValue() formatter.dateStyle = .short formatter.timeStyle = .none dict[key] = formatter.string(from: newValue) } } // 后续解码逻辑省略 }) }
处理后的字典内容
Dictionary ["timestamp": "10/22/22", "usersMatched": <__NSArrayM 0x600002c61680>( 6euZHDmI7PMDcCmft5MfxUW27jI3, tbcB0ay0YEgZcY9UsZ00WjZ9h893 ) ]
错误信息
typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "timestamp", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))
FirestoreMatch结构体定义
struct FirestoreMatch: Codable{ let usersMatched: [String] let timestamp: Date }
问题原因与解决方案
问题根源
你手动将Firestore的Timestamp类型转换为了字符串格式(如"10/22/22"),但FirestoreMatch的timestamp字段是Date类型。JSONDecoder默认会尝试将数字类型的时间戳解码为Date,遇到字符串时就会抛出类型不匹配错误。
解决方案1:使用Firebase内置的Codable解析(推荐)
移除手动转换Timestamp为字符串的循环代码,直接用Firebase提供的data(as:)方法解析文档,它会自动处理Timestamp到Date的转换:
for document in documentSnapshot.documents{ if hasFailed{ break } do { let match = try document.data(as: FirestoreMatch.self) matchList.append(match) // 后续处理逻辑 } catch { hasFailed = true onCompletion(.failure(.downloadError)) } }
解决方案2:配置JSONDecoder解析自定义日期字符串
如果坚持要保留手动转换字符串的逻辑,需要给JSONDecoder设置对应的日期解析器,让它能识别你生成的字符串格式:
let decoder = JSONDecoder() let dateFormatter = DateFormatter() dateFormatter.dateStyle = .short dateFormatter.timeStyle = .none dateFormatter.locale = Locale(identifier: "en_US_POSIX") // 确保解析格式与生成时一致 decoder.dateDecodingStrategy = .formatted(dateFormatter) // 之后再用该decoder解码数据 do { let data = try JSONSerialization.data(withJSONObject: dict) let match = try decoder.decode(FirestoreMatch.self, from: data) matchList.append(match) } catch { hasFailed = true onCompletion(.failure(.downloadError)) }
内容的提问来源于stack exchange,提问作者Anthony contreras
相关产品推荐
相关产品推荐

