Swift class和struct的解归档

NSCoding

这种方式是OC中就有的,比较老的方式,并且使用限制是只能是calss,然后实现NSCoding,对于struct是不能使用的。

internal func encode(with aCoder: NSCoder) {
        var count :UInt32 = 0
        if let ivar = class_copyIvarList(self.classForCoder, &count) {
            for i in 0..<Int(count) {
                let iv = ivar[i]
                //获取成员变量的名称 -> c语言字符串
                if let cName = ivar_getName(iv) {
                    //转换成String字符串
                    guard let strName = String(cString: cName, encoding: String.Encoding.utf8) else{
                        //继续下一次遍历
                        continue
                    }
                    //利用kvc 取值
                    let value = self.value(forKey: strName)
                    aCoder.encode(value, forKey: strName)
                }
            }
            // 释放c 语言对象
            free(ivar)
        }
    }
    
    internal required init?(coder aDecoder: NSCoder) {
        super.init()
        var count :UInt32 = 0
        if let ivar = class_copyIvarList(self.classForCoder, &count) {
            for i in 0..<Int(count) {
                let iv = ivar[i]
                //获取成员变量的名称 -》 c语言字符串
                if let cName = ivar_getName(iv) {
                    //转换成String字符串
                    guard let strName = String(cString: cName, encoding: String.Encoding.utf8) else{
                        //继续下一次遍历
                        continue
                    }
                    //进行解档取值
                    let value = aDecoder.decodeObject(forKey: strName)
                    //利用kvc给属性赋值
                    setValue(value, forKeyPath: strName)
                }
            }
            // 释放c 语言对象
            free(ivar)
        }
    }

利用运行时设置好属性,这样又多了一层限制,必须继承NSObject,因为运行时只有继承NSObject才会具备。如果不介意手动一行一行设置属性,那大可不继承NSObject。

static func saveCustomObject(customObject object: NSCoding, key: String) {
        let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
        self.userDefaults.set(encodedObject, forKey: key)
        self.userDefaults.synchronize()
    }
    
    static func removeCustomObject(key: String) {
        self.userDefaults.removeObject(forKey: key)
    }
    
    static func getCustomObject(forKey key: String) -> Any? {
        if let decodedObject = self.userDefaults.object(forKey: key), let data = decodedObject as? Data {
            let object = NSKeyedUnarchiver.unarchiveObject(with: data)
            return object
        }
        return nil
    }

这样就把class归档,解档做好了,对于struct的归档必须使用取巧的方式参考这里或者这里面,NSCoding只适用于class,系统并没有提供专门的针对struct的解归档的协议.

Swift4.0后Codable

Swift4.0后解归档就变得容易多了Codable,这个协议对于class或是struct都适用,并且使用起来很简单方便。

class ClassA: Codable {
    private var message : String? = "message"
    private var nu : String? = "nu"
    private var condition : String? = "condition"
    var com : String? = "com"
    var status : String? = "status"
    var state : String? = "state"
    var data : [ClassB]? = []
}

struct ClassB: Codable{
    var time : String? = "time"
    var ftime : String? = "ftime"
    var context : String? = "context"
    var location : String? = "location"
}

定义class和struct,只要声明实现Codable协议,不需要做额外的其他操作,比如不需要手动添加设置解归档的key等等。系统都会帮你搞定。不过需要注意的是Codable并不支持继承方式的子类解归档,也就是如果ClassC继承ClassA,如果对ClassC解归档时不会成功的,也就是说Codable不能够被继承使用,所以只能在子类实现Codable,父类不去实现Codable。

let a = ClassA()
        let b = ClassB()
        a.data = [b]
        //归档
        let encoder = JSONEncoder()
        if let data = try? encoder.encode(a) {
            print(String(data: data, encoding: .utf8)!)
            UserDefaults.standard.set(data, forKey: "piaojin")
        }
        
        let object = UserDefaults.standard.object(forKey: "piaojin")
        //解档
        let decoder = JSONDecoder()
        if let data = object as? Data {
            let objectA = try? decoder.decode(ClassA.self, from: data)
            print("\(String(describing: objectA))")
        }

这样就搞定了,关于Codable的详细介绍可以参考这里这里

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    萌萌的小伟哥阅读 721评论 0 9
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 23,682评论 30 465
  • Swift2.0 1.defer译为延缓、推迟之意类似栈 注意作用域,其次是调用顺序——即一个作用域结束(注意),...
    zeqinjie阅读 2,670评论 0 50
  • 如今,谁要是没听说过互联网+,肯定会死在今天的晚上。 行业描述 2014年我国经常参加体育锻炼的人数达到4.1亿,...
    刘明学阅读 134评论 0 1
  • 无戒365极限挑战日更营第4天 文:木子罗 这些日子,天顶渐渐的高了,云也渐渐的淡了,连天空的蓝色也透亮了,变成一...
    木子罗阅读 259评论 18 19