Save struct in class to NSUserDefaults using Swift
Solution 1
Swift structs are not classes, therefore they don't conform to AnyObject
protocol. You have to rethink your approach. Here are some suggestions:
Convert your
struct
tofinal class
to enforce immutabilityfinal class MyStruct { let start : NSDate = NSDate() let stop : NSDate = NSDate() } encoder.encodeObject(mystructs)
Map them as an array dictionaries of type
[String: NSDate]
let structDicts = mystructs.map { ["start": $0.start, "stop": $0.stop] } encoder.encodeObject(structDicts)
Solution 2
NSUserDefaults
is limited in the types it can handle: NSData
, NSString
, NSNumber
, NSDate
, NSArray
, NSDictionary
, and Bool
. Thus no Swift objects or structs can be saved. Anything else must be converted to an NSData
object.
NSUserDefaults
does not work the same way as NSArchiver
. Since you already have added NSCoder
to your classes your best choice might be to save and restore with NSArchiver
to a file in the Documents
directory..
From the Apple NSUserDefaults
Docs:
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.
Comments
-
Thomas about 2 years
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.
-
Thomas almost 10 years
let structDicts = mystructs.map { ["start": $0.start, "stop": $0.stop] }
-> fatal error: NSArray element failed to match the Swift Array Element type