我想知道是否可以使用标准的swift 4从firebase的JSON响应中编码和解码GeoPoint?
现在看来,GeoPoint不是Codable?
我收到以下错误
No 'decode' candidates produce the expected contextual result type 'GeoPoint'
在我的Codable类中
final class Data: Codable
{
var location:GeoPoint = GeoPoint(latitude:0,longitude:0)
private enum CodingKeys: String, CodingKey
{
case geoloc
}
init(from decoder: Decoder) throws
{
let values = try decoder.container(keyedBy: CodingKeys.self)
do
{
located = try values.decode(Location.self, forKey: .geoloc) //error here
}
catch
{
print("data has location in server response\n")
}
}
func encode(to encoder: Encoder) throws
{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(location, forKey: .geoloc)
}
}
答案 0 :(得分:1)
我能够扩展GeoPoint类并使其成为Codable。这就是我解决它的方式。
import UIKit
final class MyGeoPoint: GeoPoint, Codable
{
override init(latitude: Double, longitude: Double)
{
super.init(latitude: latitude, longitude: longitude)
}
private enum CodingKeys: String, CodingKey
{
case latitude = "_latitude"
case longitude = "_longitude"
}
init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: CodingKeys.self)
var lat:Double = 0
var lon:Double = 0
do
{
lat = try container.decode(Double.self, forKey: .latitude)
}
catch
{
print("no latitude for MyGeoPoint")
}
do
{
lon = try container.decode(Double.self, forKey: .longitude)
}
catch
{
print("no longitude for MyGeoPoint")
}
super.init(latitude: lat, longitude: lon)
}
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)
}
}
现在我可以使用我的原始数据类来使用我的扩展MyGeoPoint类(而不是直接使用Google的GeoPoint)来使用Google的JSON响应
final class Data: Codable
{
var location:MyGeoPoint = MyGeoPoint(latitude:0,longitude:0)
private enum CodingKeys: String, CodingKey
{
case geoloc
}
init(from decoder: Decoder) throws
{
let values = try decoder.container(keyedBy: CodingKeys.self)
do
{
//no error here anymore
location = try values.decode(MyGeoPoint.self, forKey: .geoloc)
}
catch
{
print("data has location in server response\n")
}
}
func encode(to encoder: Encoder) throws
{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(location, forKey: .geoloc)
}
}
答案 1 :(得分:0)
根据this question答案中的建议,您可以通过在Geopoint
中扩展extension
来大大简化您的代码。如果Geopoint
为struct
,则可以在以下游乐场中看到这种情况:
import Cocoa
struct Geopoint {
let longitude: Double
let latitude: Double
}
extension Geopoint : Codable {
enum CodingKeys: String, CodingKey {
case longitude, latitude
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
latitude = try values.decode(Double.self, forKey: .latitude)
longitude = try values.decode(Double.self, forKey: .longitude)
}
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)
}
}
let jsonData = """
{
"longitude": 14.334,
"latitude": 41.342
}
""".data(using: .utf8)!
do {
let point = try JSONDecoder().decode(Geopoint.self, from:jsonData)
print(point)
} catch {
print(error)
}
不像在普通Codable
中实施struct
那样轻松,但仍然很多比你提议的更少痛苦。
答案 2 :(得分:0)
我只使用基础键,然后使用坐标初始化GeoPoint
struct CustomGeoPoint : Codable {
var latitude: Double
var longitude: Double
enum CodingKeys: String, CodingKey {
case latitude = "_latitude"
case longitude = "_longitude"
}
}
答案 3 :(得分:0)
您可以使用
public typealias GeoPoint = CLLocationCoordinate2D
并将扩展名添加到 Codable 到CLLocationCoordinate2D或GeoPoint此时是相同的