ここで、このエラーを理解し、おそらくエンコード可能およびデコード可能のより広範な理解を得ることを望んでいます。クラスの一部は次のようになります。
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)
}
場所を追加するまで、このクラスは完全に機能します。すると、2つのエラーが発生します。タイプ 'CAEvent'はプロトコル 'Encodable'に準拠していません。また、fromDecoderメソッド内の 'メンバー' location 'への参照はコンテキストタイプなしでは解決できません。誰かが問題を説明できますか?
私はグーグルで 記事を見つけました 、これはコード化できないCLLocation
の実装を提供します。
その記事を読んだ後、CLLocationにDecodable
を実装することは困難です。しかし、著者はLocation
オブジェクトのデコードに別のstruct CLLocation
を使用します。面白くてトリッキーです。
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)
}
}
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)
}
}
ロケーションに含めるものに応じて、デコーダーで処理される2番目の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)
}