swift 4 firebase GeoPoint解码

时间:2018-04-25 16:30:18

标签: swift firebase firebase-realtime-database swift4 geopoints

我想知道是否可以使用标准的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)

  }
}

4 个答案:

答案 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来大大简化您的代码。如果Geopointstruct,则可以在以下游乐场中看到这种情况:

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此时是相同的