Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. Could someone explain the issue?

like image 584
AlexK Avatar asked Sep 06 '18 05:09

AlexK


People also ask

Can a protocol conform to Codable Swift?

As evident from Swift open source code, a Codable type is a type which conforms to both Decodable and Encodable protocols. It is important to note that it is not mandatory to use Codable every time for all the use-cases unless your requirement is to both serialize and de-serialize JSON response.

What is encodable and decodable in Swift?

The Codable protocol in Swift is really a union of two protocols: Encodable and Decodable . These two protocols are used to indicate whether a certain struct, enum, or class, can be encoded into JSON data, or materialized from JSON data.

What is Codable protocol?

Codable is the combined protocol of Swift's Decodable and Encodable protocols. Together they provide standard methods of decoding data for custom types and encoding data to be saved or transferred.

Is UIImage codable?

For UIImage we can use the Data type in Swift. Data is codable therefore we can use it in our wrapper.


1 Answers

I google and found an article, which provide implementations for un-codable CLLocation.

After reading that article, it's hard to implement Decodable for CLLocation. But the author use another struct Location for decoding CLLocation object. It's funny and tricky.


For 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)
    }
}
like image 67
AechoLiu Avatar answered Oct 18 '22 16:10

AechoLiu