如何将Firestore文档映射为Swift结构体?
嘿,我来帮你搞定这个问题,其实就是两个小细节出错了,咱们一步步来修正:
第一个错误:闭包类型定义完全不匹配
你一开始把闭包定义成了返回String?,但实际上你想要的是把字典转换成Address?,这直接导致了类型不匹配的核心报错。先把闭包类型改对:
let closure: ([String: Any]) -> Address? = { dictionary in return Address(dictionary: dictionary) }
不过其实你完全可以不用单独定义闭包,直接在转换逻辑里写更简洁。
第二个错误:flatMap用错了场景
你当前代码里的document.data()返回的是单个字典([String:Any]?),而flatMap对字典的默认行为是遍历它的每个键值对(也就是(key: String, value: Any)元组),这完全不是你想要的操作。
而且你要处理的是整个查询快照里的所有文档,正确的做法是遍历snapshot.documents数组,把每个文档转成Address,用compactMap过滤掉初始化失败的nil值,直接得到[Address]数组。
完整的正确代码
把这些修正后,你的代码应该写成这样:
// 假设你已经拿到了查询返回的querySnapshot var addresses = [Address]() addresses = querySnapshot.documents.compactMap { document in Address(dictionary: document.data()) }
如果一定要用单独的闭包,也可以这么写:
let addressConverter: ([String: Any]) -> Address? = { dict in Address(dictionary: dict) } var addresses = [Address]() addresses = querySnapshot.documents.compactMap { addressConverter($0.data()) }
额外提醒:你的Address初始化器有个隐藏问题
注意到你的coordinates属性是CLLocationCoordinate2D?,但Firestore无法直接存储这个类型,所以dictionary["coordinates"] as? CLLocationCoordinate2D肯定会返回nil。你需要把坐标拆成latitude和longitude两个字段存在Firestore里,然后在初始化器里手动创建坐标:
// 修改初始化器里的coordinates部分 if let lat = dictionary["latitude"] as? CLLocationDegrees, let lon = dictionary["longitude"] as? CLLocationDegrees { self.coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon) } else { self.coordinates = nil }
不然你的坐标永远都读不出来哦。
内容的提问来源于stack exchange,提问作者Jason Shultz
相关产品推荐
相关产品推荐

