Swift 4中能否用标准方式实现Firebase GeoPoint的编解码?
没错,Firebase的GeoPoint确实没有默认实现Codable协议,所以直接在自定义的Codable类里使用它会触发你遇到的解码错误。不过我们有两种简单的解决方案,帮你搞定这个问题:
方案一:在自定义类中手动实现编码解码逻辑
首先注意下,Data是Swift系统自带的类型,建议把你的类名改成DataModel之类的,避免命名冲突。然后我们可以手动处理GeoPoint的解码和编码:
final class DataModel: Codable { var location: GeoPoint = GeoPoint(latitude: 0, longitude: 0) // 对应JSON里的"geoloc"字段 private enum CodingKeys: String, CodingKey { case geoloc } // 解析GeoPoint内部的纬度、经度字段 private enum GeoPointKeys: String, CodingKey { case latitude, longitude } // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 取出"geoloc"对应的嵌套容器 let geoContainer = try container.nestedContainer(keyedBy: GeoPointKeys.self, forKey: .geoloc) // 解码纬度和经度 let latitude = try geoContainer.decode(Double.self, forKey: .latitude) let longitude = try geoContainer.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) // 创建"geoloc"对应的嵌套容器 var geoContainer = container.nestedContainer(keyedBy: GeoPointKeys.self, forKey: .geoloc) // 编码纬度和经度 try geoContainer.encode(location.latitude, forKey: .latitude) try geoContainer.encode(location.longitude, forKey: .longitude) } }
方案二:给GeoPoint扩展Codable协议
如果你的项目里很多地方都要用到GeoPoint的编解码,更高效的方式是直接给GeoPoint扩展Codable,这样所有用到它的Codable类都能自动处理:
extension GeoPoint: Codable { private enum CodingKeys: String, CodingKey { case latitude, longitude } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let latitude = try container.decode(Double.self, forKey: .latitude) let longitude = try container.decode(Double.self, forKey: .longitude) self.init(latitude: latitude, longitude: longitude) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(latitude, forKey: .latitude) try container.encode(longitude, forKey: .longitude) } }
扩展之后,你的自定义类就可以简化成这样,不用再手动写编解码逻辑:
final class DataModel: Codable { // 直接把JSON里的"geoloc"映射到location属性 var location: GeoPoint = GeoPoint(latitude: 0, longitude: 0) private enum CodingKeys: String, CodingKey { case location = "geoloc" } }
两种方案都能解决你遇到的问题,根据你的项目需求选择就好~
内容的提问来源于stack exchange,提问作者aman
相关产品推荐
相关产品推荐

