[英]Save struct in class to NSUserDefaults using Swift
我有一個類,類內部是一個(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數組。 兩者都是我不想做的事情。
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)
NSUserDefaults
處理類型有限: NSData
, NSString
, NSNumber
, NSDate
, NSArray
, NSDictionary
和Bool
。 因此, 不能保存Swift對象或結構。 必須將其他任何內容轉換為NSData
對象。
NSUserDefaults
與NSArchiver
工作方式不同。 由於您已經將NSCoder
添加到您的類中,因此您最好的選擇可能是使用NSArchiver
將其保存和恢復到Documents
目錄中的Documents
。
來自Apple NSUserDefaults
文檔:
默認對象必須是屬性列表,即(或集合的實例組合)的實例:NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。 如果要存儲任何其他類型的對象,通常應將其存檔以創建NSData實例。
我開發了一個可能有用的小型庫 。 您可以將它用作Swift結構的NSCoding
的替代品。
您需要為mystruct
實現Koting
協議:
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結構,那么你將編寫的代碼幾乎相同。
我在使用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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.