xcode “X”型不符合“Encodable”协议
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/52197237/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Type 'X' does not conform to protocol 'Encodable'
提问by Alex Kornhauser
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?
这个类工作完美,直到我添加位置。当我这样做时,我收到两个错误:类型“CAEvent”不符合协议“Encodable”,并且在 fromDecoder 方法中,如果没有上下文类型,就无法解析“对成员“位置”的引用。有人可以解释这个问题吗?
回答by AechoLiu
I google and found an article, which provide implementations for un-codable CLLocation.
我用谷歌搜索并找到了一篇文章,其中提供了 un-codable 的实现CLLocation。
After reading that article, it's hard to implement Decodablefor CLLocation. But the author use another struct Locationfor decoding CLLocationobject. It's funny and tricky.
看完那篇文章后,DecodableCLLocation很难实现。但是作者使用另一个结构Location来解码CLLocation对象。这很有趣也很棘手。
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)
}
}
回答by Steve O'Connor
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. This isn't decoding a complete CLLocation but might be all you need
根据您希望位置包含的内容,您可以添加第二个 JSON 兼容变量,该变量在解码器中处理以创建 CLLocation。这不是解码完整的 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)
}
}

