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 Decodable
for CLLocation. But the author use another struct Location
for decoding CLLocation
object. It's funny and tricky.
看完那篇文章后,Decodable
CLLocation很难实现。但是作者使用另一个结构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)
}
}