【问题标题】:swift 4 firebase GeoPoint decodeswift 4 firebase GeoPoint 解码
【发布时间】:2018-10-06 05:17:42
【问题描述】:

我想知道是否可以使用标准 swift 4 从 firebase 的 JSON 响应中对 GeoPoint 进行编码和解码?

现在看来,GeoPoint 是不可编码的?

我收到以下错误

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)

  }
}

【问题讨论】:

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


    【解决方案1】:

    我能够扩展 GeoPoint 类并使其可编码。我就是这样解决的。

    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)
      }
    
    }
    

    现在我可以使用我的原始 Data 类来使用来自 Google 的 JSON 响应,使用我的扩展 MyGeoPoint 类(而不是直接使用 Google 的 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)
    
      }
    }
    

    【讨论】:

      【解决方案2】:

      按照this question 答案中的建议,您可以通过在extension 中扩展Geopoint 来大大简化您的代码。如果Geopointstruct,这甚至是可能的,如以下 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 那样轻松,但仍然比你建议的痛苦少很多

      【讨论】:

        【解决方案3】:

        我只使用底层键,然后用坐标初始化 GeoPoint

        struct CustomGeoPoint : Codable {
        
            enum CodingKeys: String, CodingKey {
                case latitude 
                case longitude
            }
        
            var latitude: Double
            var longitude: Double
        }
        

        【讨论】:

          【解决方案4】:

          如果你想使用它,你可以使用它

          public typealias GeoPoint = CLLocationCoordinate2D
          

          并将 Codable 的扩展添加到 CLLocationCoordinate2D 或 GeoPoint 在这一点上是相同的

          【讨论】:

            猜你喜欢
            • 2018-07-15
            • 1970-01-01
            • 1970-01-01
            • 2016-05-28
            • 1970-01-01
            • 1970-01-01
            • 2019-01-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多