Reputation: 37
I am trying to store an array of a custom class using UserDefaults
. The custom class is for annotations using a mixture of strings and CLLocationCoordinate2D
.
I am calling ArchiveUtil.savePins(pins: pins)
when I perform a long press gesture in the Map View.
However, I am getting an error
-[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs'
Any ideas what I am doing wrong?
Thanks, code below:
class PinLocation: NSObject, NSCoding, MKAnnotation {
var title: String?
var subtitle: String?
var coordinate: CLLocationCoordinate2D
init(name:String, description: String, lat:CLLocationDegrees,long:CLLocationDegrees){
title = name
subtitle = description
coordinate = CLLocationCoordinate2DMake(lat, long)
}
required init?(coder aDecoder: NSCoder) {
title = aDecoder.decodeObject(forKey: "title") as? String
subtitle = aDecoder.decodeObject(forKey: "subtitle") as? String
coordinate = aDecoder.decodeObject(forKey: "coordinate") as! CLLocationCoordinate2D
}
func encode(with aCoder: NSCoder) {
aCoder.encode(title, forKey: "title")
aCoder.encode(subtitle, forKey: "subtitle")
aCoder.encode(coordinate, forKey: "coordinate")
}
}
class ArchiveUtil {
private static let PinKey = "PinKey"
private static func archivePins(pin: [PinLocation]) -> NSData{
return NSKeyedArchiver.archivedData(withRootObject: pin as NSArray) as NSData
}
static func loadPins() -> [PinLocation]? {
if let unarchivedObject = UserDefaults.standard.object(forKey: PinKey) as? Data{
return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [PinLocation]
}
return nil
}
static func savePins(pins: [PinLocation]?){
let archivedObject = archivePins(pin: pins!)
UserDefaults.standard.set(archivedObject, forKey: PinKey)
UserDefaults.standard.synchronize()
}
}
Upvotes: 2
Views: 300
Reputation: 285072
The error is pretty clear: CLLocationCoordinate2D
is a struct
and this archiver cannot encode structs.
A simple workaround is to en- and decode latitude
and longitude
separately.
By the way, since both String
properties are initialized with non-optional values declare them also as non-optional. If they are supposed not to be changed declare them even as constant (let
)
var title: String
var subtitle: String
...
required init?(coder aDecoder: NSCoder) {
title = aDecoder.decodeObject(forKey: "title") as! String
subtitle = aDecoder.decodeObject(forKey: "subtitle") as! String
let latitude = aDecoder.decodeDouble(forKey: "latitude")
let longitude = aDecoder.decodeDouble(forKey: "longitude")
coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(title, forKey: "title")
aCoder.encode(subtitle, forKey: "subtitle")
aCoder.encode(coordinate.latitude, forKey: "latitude")
aCoder.encode(coordinate.longitude, forKey: "longitude")
}
Upvotes: 2