在Swift中为FIRGeoPoint适配Codable协议并构建Firestore文档模型
实现Firestore文档到Codable结构体的映射(包含GeoPoint类型)
刚好碰到过类似的问题!Firebase的GeoPoint默认并没有实现Codable协议,所以我们需要手动给结构体添加自定义的编码和解码逻辑来处理它。下面是完整的实现代码,我会一步步拆解说明:
import FirebaseFirestore struct TestStruct: Codable { // 和Firestore文档对应的属性 let name: String let aNumber: Double let location: GeoPoint // 定义编码解码的键,要和Firestore文档里的字段名完全一致 enum CodingKeys: String, CodingKey { case name, location, aNumber } // 自定义解码逻辑 init(from decoder: Decoder) throws { // 获取顶层解码容器 let container = try decoder.container(keyedBy: CodingKeys.self) // String和Number类型可以直接解码,没有特殊处理 name = try container.decode(String.self, forKey: .name) aNumber = try container.decode(Double.self, forKey: .aNumber) // 处理GeoPoint:先取出它的嵌套容器,读取经纬度值 let locationContainer = try container.nestedContainer(keyedBy: GeoPointCodingKeys.self, forKey: .location) let latitude = try locationContainer.decode(Double.self, forKey: .latitude) let longitude = try locationContainer.decode(Double.self, forKey: .longitude) // 用经纬度初始化GeoPoint实例 location = GeoPoint(latitude: latitude, longitude: longitude) } // 自定义编码逻辑 func encode(to encoder: Encoder) throws { // 获取顶层编码容器 var container = encoder.container(keyedBy: CodingKeys.self) // 直接编码String和Number类型 try container.encode(name, forKey: .name) try container.encode(aNumber, forKey: .aNumber) // 编码GeoPoint:创建嵌套容器,写入经纬度 var locationContainer = container.nestedContainer(keyedBy: GeoPointCodingKeys.self, forKey: .location) try locationContainer.encode(location.latitude, forKey: .latitude) try locationContainer.encode(location.longitude, forKey: .longitude) } // 内部枚举,用来对应GeoPoint对象里的经纬度键名 private enum GeoPointCodingKeys: String, CodingKey { case latitude, longitude } }
关键说明:
CodingKeys枚举必须和Firestore文档的字段名严格匹配,不然会解码失败。- 对于
GeoPoint,我们通过嵌套容器来读取/写入它的latitude和longitude属性,因为Firestore存储GeoPoint时,底层是包含这两个字段的对象结构。 - 自定义
init(from:)和encode(to:)方法后,这个结构体就可以直接配合Firestore的API使用了。
使用示例:
当你从Firestore获取到DocumentSnapshot后,可以直接用data(as:)方法解码成TestStruct实例:
func fetchTestDocument() { let db = Firestore.firestore() db.collection("testCollection").document("testDoc").getDocument { snapshot, error in guard let snapshot = snapshot, snapshot.exists else { return } do { let testItem = try snapshot.data(as: TestStruct.self) print("解码结果:\(testItem.name), \(testItem.aNumber), \(testItem.location)") } catch { print("解码出错:\(error.localizedDescription)") } } }
内容的提问来源于stack exchange,提问作者Arda Oğul Üçpınar
相关产品推荐
相关产品推荐

