我有一个类,类里面是一个基于全局结构的(swift)数组。 我想将此类的数组保存到NSUserDefaults。这是我的代码:
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()
}
}
我已经将子类化为NSObject,我知道我需要NSCoding。但我没有找到任何方法将struct数组转换为NSMuteableArray或类似的东西我可以存储。直到现在唯一的想法是遍历每个条目并将其直接复制到新数组或在整个项目中使用大量或客观的代码,因此我永远不需要从swift数组转换为objective-c数组。两者都是我不想做的事情。
答案 0 :(得分:10)
Swift结构不是类,因此它们不符合AnyObject
协议。你必须重新思考你的方法。以下是一些建议:
将您的struct
转换为final class
以强制执行不变性
final class MyStruct {
let start : NSDate = NSDate()
let stop : NSDate = NSDate()
}
encoder.encodeObject(mystructs)
将它们映射为[String: NSDate]
let structDicts = mystructs.map { ["start": $0.start, "stop": $0.stop] }
encoder.encodeObject(structDicts)
答案 1 :(得分:6)
NSUserDefaults
的处理类型有限:NSData
,NSString
,NSNumber
,NSDate
,NSArray
,{{1 }和NSDictionary
。因此,没有可以保存Swift对象或结构。必须将其他任何内容转换为Bool
对象。
NSData
与NSUserDefaults
的工作方式不同。由于您已经在类中添加了NSArchiver
,因此最好的选择可能是使用NSCoder
保存并还原到NSArchiver
目录中的文件。
来自Apple Documents
文档:
默认对象必须是属性列表,即(或 对于集合的实例组合):NSData,NSString, NSNumber,NSDate,NSArray或NSDictionary。如果你想存储任何 在其他类型的对象中,通常应将其存档以创建 NSData的实例。
答案 2 :(得分:0)
我开发了a small library可能有所帮助。您可以将其用作Swift结构的NSCoding
的替代。
您需要为Koting
实施mystruct
协议:
struct mystruct: Koting {
var start : NSDate = NSDate()
var stop : NSDate = NSDate()
// MARK: - Koting
init?(koter: Koter) {
guard let start: NSDate = koter.dekotObject(forKey: "start"),
let stop: NSDate = koter.dekotObject(forKey: "stop") else {
return nil
}
self.init(start: start, stop: stop)
}
func enkot(with koter: Koter) {
koter.enkotObject(start, forKey: "start")
koter.enkotObject(stop, forKey: "stop")
}
}
从那时起,您可以轻松地将结构转换为Data
并返回:
let str = mystruct(start: NSDate(/*...*/), stop: NSDate(/*...*/))
guard let data = str.de_data else { return } // potentially may be nil
let restoredStr = mystruct.de_from(data: data) // if data is irrelevant, returns `nil`
最后,这是您实施NSCoding
:
class MyClass: NSObject, NSCoding {
var mystructs: [mystruct]
init(mystructs: [mystruct]) {
self.mystructs = mystructs
super.init()
}
func encode(with aCoder: NSCoder) {
guard let datas = mystructs.flatMap { $0.de_data } else { return }
aCoder.encode(datas, forKey: "mystructs")
}
required convenience init?(coder aDecoder: NSCoder) {
guard let datas = aDecoder.decodeObject(forKey: "mystructs") as? [Data],
let mystructs = datas.flatMap { mystruct.de_from(data: $0) } else {
return nil
}
self.init(mystructs : mystructs)
}
}
如果NSCoding
支持Swift结构,那么你编写的代码几乎相同。
答案 3 :(得分:0)
我在用Swift 4编码时在我的项目中使用了这个:
let jsonData = """ {"variable1":1234,"variable2":"someString"}"""
struct MyStruct:Codable{
var variable1 :Int
var variable2:String
}
let whatever = try JSONDecoder().decode(MyStruct.self,from:jsonData)
let encoded =try JSONEncoder().encode(whatever)
UserDefaults.standart.set(encoded, forKey:"encodedData")
从UserDefaults中获取数据
if let data = UserDefaults.standard.object(forKey: "encodedData") as? Data {
let myStruct = try JSONDecoder().decode(MyStruct.self, from: data)
print(myStruct)
}