I have a struct that contains an array of arrays of CLLocations. This is to support a multipolyline (in other words, a bunch of potentially discontiguous lines). I wish to encode and decode this data. I am having trouble writing the encoding and decoding methods as CLLocation is not codable by default.
struct MyTrack {
let coords: [[CLLocation]]?
enum CodingKeys: String, CodingKey {
case coords
}
}
extension MyTrack: Decodable {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
coords = try values.decodeIfPresent([[CLLocation]].self, forKey: .coords)?
.map { ($0 as AnyObject).map { CLLocation(model: $0) } }
}
}
Its currently throwing two errors in Xcode:
Cannot convert value of type '[[CLLocation]].Type' to expected argument type '[Any?].Type'
Value of type 'AnyObject' has no member 'map'
Any help much appreciated!
Because CLLocation is not Codable by default, I followed a tutorial to create a wrapper struct around it, the code goes like this:
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)
}
}
You are decoding CLLocation
, not your wrapper struct. You should decode your wrapper struct instead. Also, you shouldn't cast to AnyObject
.
extension MyTrack: Decodable {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
coords = try values.decodeIfPresent([[Location]].self, forKey: .coords)?
.map { $0.map(CLLocation.init) }
}
}