swift 4 firebase GeoPoint 解码
swift 4 firebase GeoPoint decode
我想知道是否可以使用标准 swift 4 从 firebase 的 JSON 响应编码和解码 GeoPoint?
目前看来 GeoPoint 不可编码?
我收到以下错误
No 'decode' candidates produce the expected contextual result type 'GeoPoint'
在我的 Codable 中 class
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)
}
}
我能够扩展 GeoPoint class 并使其可编码。我就是这样解决的。
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)
}
}
现在我可以使用我的原始数据 class 使用扩展的 MyGeoPoint class(而不是 Google 使用来自 Google 的 JSON 响应的 GeoPoint 直接)
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)
}
}
按照 答案中的建议,您可以通过在 extension
中扩展 Geopoint
来大大简化您的代码。如果 Geopoint
是 struct
,这甚至是可能的,如以下 Playground 所示:
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)
}
不像在普通 struct
中实施 Codable
那样轻松,但仍然 很多 比您建议的要轻松得多。
我只使用底层键,然后用坐标初始化 GeoPoint
struct CustomGeoPoint : Codable {
enum CodingKeys: String, CodingKey {
case latitude
case longitude
}
var latitude: Double
var longitude: Double
}
如果你想用那个就可以
public typealias GeoPoint = CLLocationCoordinate2D
并将Codable的扩展添加到CLLocationCoordinate2D或GeoPoint,此时相同
我想知道是否可以使用标准 swift 4 从 firebase 的 JSON 响应编码和解码 GeoPoint?
目前看来 GeoPoint 不可编码?
我收到以下错误
No 'decode' candidates produce the expected contextual result type 'GeoPoint'
在我的 Codable 中 class
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)
}
}
我能够扩展 GeoPoint class 并使其可编码。我就是这样解决的。
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)
}
}
现在我可以使用我的原始数据 class 使用扩展的 MyGeoPoint class(而不是 Google 使用来自 Google 的 JSON 响应的 GeoPoint 直接)
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)
}
}
按照 extension
中扩展 Geopoint
来大大简化您的代码。如果 Geopoint
是 struct
,这甚至是可能的,如以下 Playground 所示:
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)
}
不像在普通 struct
中实施 Codable
那样轻松,但仍然 很多 比您建议的要轻松得多。
我只使用底层键,然后用坐标初始化 GeoPoint
struct CustomGeoPoint : Codable {
enum CodingKeys: String, CodingKey {
case latitude
case longitude
}
var latitude: Double
var longitude: Double
}
如果你想用那个就可以
public typealias GeoPoint = CLLocationCoordinate2D
并将Codable的扩展添加到CLLocationCoordinate2D或GeoPoint,此时相同