简体   繁体   English

类型'X'不符合协议'Encodable'

[英]Type 'X' does not conform to protocol 'Encodable'

I am hoping here to get an understanding of this error and perhaps a broader understanding of encodable and decodable. 我希望在这里能够理解这个错误,并且可能对可编码和可解码的更广泛理解。 Part of my class looks as follows: 我班级的一部分如下:

  public var eventId: String?
  public var eventName: String?
  public var eventDescription: String?
  public var location: CLLocation?

  /// These properties will be encoded/decoded from JSON
  private enum CodingKeys: String, CodingKey {
    case eventId
    case eventName
    case eventDescription
    case location
  }

  public required convenience init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    let eventId = try container.decode(String?.self, forKey: .eventId)
    let eventName = try container.decode(String?.self, forKey: .eventName)
    let location = try container.decode(CLLocation?.self, forKey: .location)
    self.init(eventId: eventId, eventName: eventName, location:location)
  }

This class works perfectly, until I add location. 这个类非常有效,直到我添加位置。 When I do I get two errors: Type 'CAEvent' does not conform to protocol 'Encodable', and 'Reference to member 'location' cannot be resolved without a contextual type' inside the fromDecoder method. 当我这样做时,我得到两个错误:类型'CAEvent'不符合协议'可编码',并且在fromDecoder方法内没有上下文类型'无法解析'引用成员'位置'。 Could someone explain the issue? 有人可以解释这个问题吗?

I google and found an article , which provide implementations for un-codable CLLocation . 我google并发现了一篇文章 ,它提供了不可编码CLLocation

After reading that article, it's hard to implement Decodable for CLLocation. 阅读该文章后,很难为CLLocation实现Decodable But the author use another struct Location for decoding CLLocation object. 但是作者使用另一个struct Location来解码CLLocation对象。 It's funny and tricky. 这很有趣也很棘手。


For Encodable 对于Encodable

extension CLLocation: Encodable {
    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
        case altitude
        case horizontalAccuracy
        case verticalAccuracy
        case speed
        case course
        case timestamp
    }
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(coordinate.latitude, forKey: .latitude)
        try container.encode(coordinate.longitude, forKey: .longitude)
        try container.encode(altitude, forKey: .altitude)
        try container.encode(horizontalAccuracy, forKey: .horizontalAccuracy)
        try container.encode(verticalAccuracy, forKey: .verticalAccuracy)
        try container.encode(speed, forKey: .speed)
        try container.encode(course, forKey: .course)
        try container.encode(timestamp, forKey: .timestamp)
    }
}

For Decodable 对于可解码

struct Location: Codable {
    let latitude: CLLocationDegrees
    let longitude: CLLocationDegrees
    let altitude: CLLocationDistance
    let horizontalAccuracy: CLLocationAccuracy
    let verticalAccuracy: CLLocationAccuracy
    let speed: CLLocationSpeed
    let course: CLLocationDirection
    let timestamp: Date
}
extension CLLocation {
    convenience init(model: Location) {
      self.init(coordinate: CLLocationCoordinate2DMake(model.latitude, model.longitude), altitude: model.altitude, horizontalAccuracy: model.horizontalAccuracy, verticalAccuracy: model.verticalAccuracy, course: model.course, speed: model.speed, timestamp: model.timestamp)
     }
}


/// 
struct Person {
    let name: String
    let location: CLLocation
    enum CodingKeys: String, CodingKey {
        case name
        case location
    }
}
extension Person: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)           
        let name = try values.decode(String.self, forKey: .name)

        // Decode to `Location` struct, and then convert back to `CLLocation`. 
        // It's very tricky
        let locationModel = try values.decode(Location.self, forKey: .location)
        location = CLLocation(model: locationModel)
    }
}

Depending on what you want your location to contain, you could add a second JSON compatible variable which is handled in the decoder to create a CLLocation. 根据您希望位置包含的内容,您可以添加第二个JSON兼容变量,该变量在解码器中处理以创建CLLocation。 This isn't decoding a complete CLLocation but might be all you need 这不是解码完整的CLLocation,但可能就是您所需要的

public var eventId: String?
public var eventName: String?
public var eventDescription: String?
public var location: [Float]? // latitude, longitude
public var cllocation: CLLocation?

/// These properties will be encoded/decoded from JSON
private enum CodingKeys: String, CodingKey {
case eventId
case eventName
case eventDescription
case location
}

public required convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

let eventId = try container.decode(String?.self, forKey: .eventId)
let eventName = try container.decode(String?.self, forKey: .eventName)
let location = try container.decode([Float]?.self, forKey: .location)
let cllocation = CLLocation(latitude: CLLocationDegrees(location[0]), CLLocationDegrees(longitude[1]))
self.init(eventId: eventId, eventName: eventName, location:cllocation)

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM