2019-03-22Swift4.2中使用归档解档存储用户数据(使用运行时机制,获取属性列表)

我们先看看使用归档和解档需要遵守的几个条件

条件:

  • 归档解档存储的对象必须是class,而不是结构体。使用结构体可以用协议方法去实现,请有意者自行查资料。
  • 该class需要继承NSObject,才可以使用KVC的方法,通过key拿到值或者通过key赋值。这是一个牺牲,不想继承的使用UserDafult方法去存储,毕竟Swift里面少点oc东西好
  • 如果想通过运行时一次获得所有属性列表,更方便的进行归档和解档里面的kvc操作,需要在类前面加上@objcMembers修饰符 , 注意使用kvc获得json数据的时候需要在每个属性上面加上@objc 不然会出现key not founds错误
  • 如@objcMembers class UserAccount :NSObject,NSCoding,Codable{...}这样去声明一个类。

所谓运行时获取属性,就是能一次性拿到该类的所有属性名字(他们都被存储在该对象isa指针指向的objc_class)里面,是里面的一个数组。

下面看获得属性列表的方法

   func getPropertyNameList() -> [String] {
        
        var count : UInt32 = 0
        
        var names : [String] = []
        
        let properties = class_copyPropertyList(type(of: self), &count)
        
        guard let propertyList = properties else {
            return []
        }
        
        for i in 0..<count{
            let property = propertyList[Int(i)]
            
            let char_b = property_getName(property)
            //这里转一下encoding,转成utf8的key
            if let key = String.init(cString: char_b, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) as String?{
                names.append(key)
            }
            
        }
        
        return names
    }

获得我们这个属性列表后,我们就可以在重写的encode和decode方法的时候,直接去使用这个数组去初始化所有成员变量了。

下面是encode和decode方法

  ///归档数据存储到磁盘
    func encode(with aCoder: NSCoder)  {
        
        let propertyList = getPropertyNameList()
        
                print(propertyList)
        
        propertyList.forEach { (p_name) in
            print("\(p_name) + \(String(describing: value(forKey: p_name)))")
            aCoder.encode(value(forKey: p_name), forKey: p_name)
        }
        //下面是没有通过ivars获得属性列表的情况
        //aCoder.encode(access_token, forKey: "access_token")
        //        aCoder.encode(expiresDate, forKey: "expiresDate")
        //        aCoder.encode(uid, forKey: "uid")
        //        aCoder.encode(screen_name, forKey: "screen_name")
        //        aCoder.encode(avatar_large, forKey: "avatar_large")
    }
    
    required init?(coder aDecoder: NSCoder) {
        
        super.init()
        
        let propertyList = getPropertyNameList()
        
        print(propertyList)
        
        propertyList.forEach { (p_name) in
            let value = aDecoder.decodeObject(forKey: p_name)
                        print("\(p_name) + \(String(describing: value))")
            setValue(value, forKey: p_name)
        }
        //access_token = aDecoder.decodeObject(forKey: "access_token") as? String
        //        expiresDate = aDecoder.decodeObject(forKey: "expiresDate") as? Date
        //        uid = aDecoder.decodeObject(forKey: "uid") as? String
        //        screen_name = aDecoder.decodeObject(forKey: "screen_name") as? String
        //        avatar_large = aDecoder.decodeObject(forKey: "avatar_large") as? String
    }

然后这时候我们在外面把该类对象写入磁盘(归档)和解档就会调用上面的encode 和 decode方法

下面来介绍一下Swift4.2的NSKeyedArchiver和NSKeyedUnArchiver的新使用方法

NSKeyedArchiver.archiveRootObject(, toFile: )
这个方法已经过期了。
注意方法返回是可能throw的,我们需要用try去使用这个函数
swift更希望我们使用下面这种do catch的结合,这样我们可以更好的对不同错误进行补抓和处理,而且代码结构也更好看。

do {
                let data = try NSKeyedArchiver.archivedData(withRootObject: account, requiringSecureCoding: false)
                do{
                    try data.write(to: self.accountPath)
                }
                catch{
                    assert(true, "无法把account写入path")
                }
            }catch{
                    assert(true, "无法生成归档数据")
            }

我们只能通过先把对象归档成一个data,再把data写入磁盘,而不是像之前那种一步写入。

下面看看解档

 do {

            let data = try Data.init(contentsOf: accountPath)

            do{
// NSKeyedArchiver.archivedData(withRootObject: account, requiringSecureCoding: false)与下面方法配套使用
                 account = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UserAccount
            }
            catch{
                assert(true, "用户数据解档失败")
            }
        } catch {
            assert(true, "用户数据解档路径错误")
        }

注意NSKeyedArchiver.archivedData(withRootObject:,requiringSecureCoding)和 NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)

要配套使用! 要配套使用!要配套使用!

你怎么归的档,就怎么解档,不然乱搭配他会无法解档,虽然你文件就是在那个目录,我那天就是因为用错方法调试了一天。。。 还有data.writeTo(Path:)这个要注意你传入URL的初始化的时候,是文件路径还是网络路径,这个也别搞错了,不然归档和解档可能出现位置错误。
Swift会越来越有自己的编程规范~~ 希望ios越做越好!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335