繁体   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