Xcode中Decodable配合compactMap返回IGNotification空数组问题排查
空数组返回原因及解决方案
你返回空数组的核心原因是compactMap会过滤掉所有解码失败返回的nil值,只要所有IGNotification初始化失败,最终结果就是空数组,你可以按照以下步骤排查:
1. 优先排查解码失败问题
你自定义的Decodable可失败初始化器存在两处容易触发失败的逻辑,任意一处失败都会返回nil被过滤:
- JSONSerialization生成数据失败:如果Firestore返回的字段里包含Timestamp、GeoPoint、DocumentReference等Firestore专属特殊类型,
JSONSerialization无法正常将其转换为JSON格式数据,会触发第一个guard判断失败返回nil
解决方法:不要自己实现字典转模型的逻辑,引入官方库FirebaseFirestoreSwift,直接使用原生支持Firestore类型的解码器,示例代码:// 解码单条文档的写法,不需要自己写Decodable扩展 try? document.data(as: IGNotification.self) - JSONDecoder解码模型失败:如果你的
IGNotification模型的属性名、属性类型和Firestore中存储的字段不匹配,会触发解码失败返回nil
解决方法:将初始化器中的try?替换为do-catch捕获具体错误,即可定位到不匹配的字段:init?(with dictionary: [String: Any]) { do { let data = try JSONSerialization.data(withJSONObject: dictionary) self = try JSONDecoder().decode(Self.self, from: data) } catch { print("解码错误详情:\(error)") return nil } }
2. 排查Firestore查询本身无数据的问题
如果解码逻辑没有问题,需要确认查询是否真的拿到了文档数据:
- 打印
snapshot?.documents.count验证返回的文档数量,如果为0说明查询路径错误:确认UserDefaults中存储的username是否正确,对应路径下的notifications集合是否真的存在数据 - 打印
error参数验证是否有权限问题:如果Firestore安全规则没有开放该集合的读权限,会返回权限错误,导致拿不到数据
优化后的代码示例
import FirebaseFirestoreSwift public func getNotifications( completion: @escaping ([IGNotification]) -> Void ) { guard let username = UserDefaults.standard.string(forKey: "username") else { completion([]) return } let ref = firestoreDatabase.collection("users").document(username).collection("notifications") ref.getDocuments { snapshot, error in if let error = error { print("查询错误:\(error)") completion([]) return } guard let documents = snapshot?.documents else { completion([]) return } let notifications = documents.compactMap { try? $0.data(as: IGNotification.self) } completion(notifications) } }
内容的提问来源于stack exchange,提问作者Swimmer97
相关产品推荐
相关产品推荐

