簡體   English   中英

使用Swift將類中的struct保存到NSUserDefaults

[英]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協議。 你必須重新思考你的方法。 以下是一些建議:

  1. 將您的struct轉換為final class以強制實現不變性

     final class MyStruct { let start : NSDate = NSDate() let stop : NSDate = NSDate() } encoder.encodeObject(mystructs) 
  2. 將它們映射為[String: NSDate]類型的數組字典

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

NSUserDefaults處理類型有限: NSDataNSStringNSNumberNSDateNSArrayNSDictionaryBool 因此, 不能保存Swift對象或結構。 必須將其他任何內容轉換為NSData對象。

NSUserDefaultsNSArchiver工作方式不同。 由於您已經將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM