Save struct in class to NSUserDefaults using Swift

Thomas picture Thomas · Aug 28, 2014 · Viewed 12.5k times · Source

I have a class and inside the class is a (swift) array, based on a global struct. I want to save an array with this class to NSUserDefaults. This is my code:

struct mystruct {
    var start : NSDate = NSDate()
    var stop : NSDate = NSDate()
}

class MyClass : NSObject {

    var mystructs : [mystruct]

    init(mystructs : [mystruct]) {

        self.mystructs = mystructs 
        super.init()
    }

    func encodeWithCoder(encoder: NSCoder) {
        //let val = mystructs.map { $0 as NSObject } //this also doesn't work
        let objctvtmrec = NSMutableArray(mystructs)  //gives error
        encoder.encodeObject(objctvtmrec)
        //first approach:
        encoder.encodeObject(mystructs) //error: [mystructs] doesn't conform to protocol 'anyobject'
    }

}

var records : [MyClass] {
    get {
        var returnValue : [MyClass]? = NSUserDefaults.standardUserDefaults().objectForKey("records") as? [MyClass]
        if returnValue == nil
        {
            returnValue = []
        }
        return returnValue!
    }
    set (newValue) {
        let val = newValue.map { $0 as AnyObject }
        NSUserDefaults.standardUserDefaults().setObject(val, forKey: "records")
        NSUserDefaults.standardUserDefaults().synchronize()
    }
}

I already subclassed to NSObject, and I know I need NSCoding. But I don't find any way to convert the struct array to an NSMuteableArray or something similar I can store. The only idea until now is to go through each entry and copy it directly to a new array or to use much or objective-c code all over the project, so i never need to convert from swift arrays to objective-c arrays. Both are things I don't want to do.

Answer

akashivskyy picture akashivskyy · Aug 28, 2014

Swift structs are not classes, therefore they don't conform to AnyObject protocol. You have to rethink your approach. Here are some suggestions:

  1. Convert your struct to final class to enforce immutability

    final class MyStruct {
        let start : NSDate = NSDate()
        let stop : NSDate = NSDate()
    }
    
    encoder.encodeObject(mystructs)
    
  2. Map them as an array dictionaries of type [String: NSDate]

    let structDicts = mystructs.map { ["start": $0.start, "stop": $0.stop] }
    encoder.encodeObject(structDicts)