mathleticolewis
mathleticolewis

Reputation: 37

custom class storage - cannot encode structs

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

Answers (1)

vadian
vadian

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

Related Questions