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.
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 immutabilityMap them as an array dictionaries of type
[String: NSDate]
NSUserDefaults
is limited in the types it can handle:NSData
,NSString
,NSNumber
,NSDate
,NSArray
,NSDictionary
, andBool
. Thus no Swift objects or structs can be saved. Anything else must be converted to anNSData
object.NSUserDefaults
does not work the same way asNSArchiver
. Since you already have addedNSCoder
to your classes your best choice might be to save and restore withNSArchiver
to a file in theDocuments
directory..From the Apple
NSUserDefaults
Docs:I use this this in my project while coding with Swift 4:
let jsonData = """ {"variable1":1234,"variable2":"someString"}"""
struct MyStruct:Codable{ var variable1 :Int var variable2:String }
to fetch data from UserDefaults
I've developed a small library which may help. You can use it as a replacement of
NSCoding
for Swift structs.You would need to implement a
Koting
protocol formystruct
:Since then you may easily convert the struct to
Data
and back:Finally, this is what you do to implement
NSCoding
:It's pretty much the same code you would write if
NSCoding
supported Swift structs.