iOS数据持久化之二——归档与设计可存储化的数据模型基类
一、引言
在上一篇博客中,我们介绍了用plist文件进行数据持久化的方法。虽然简单易用,但随着开发的深入,你会发现,这种方式还是有很大的局限性。试想,如果我们可以将用户的登录返回信息模型,游戏中角色的属性信息模型进行直接的持久化存取,那是不是非常爽的事,幸运的是,我们可以通过归档,来设计一个这样的数据模型。
二、先来精通归档吧
归档也是iOS提供给开发者的一种数据存储的方式,事实上,几乎所有的数据类型都可以通过归档来进行存取。其存储与读取的过程,主要封装在两个类中:NSKeyedArchiver和NSKeyedUnarchiver。
1、归档的原理
归档是将一种或者多种数据类型进行序列化,解归档的过程就是将序列化的数据进行反序列化的解码,这里需要注意一点,归档的核心并非是数据的持久化处理,而是数据的序列化处理,持久化的处理依然是通过文件存取来实现的。因此,被归档的数据类型都必须遵守一个相同的协议,才能在这个协议的约束下进行正确的归档与解归档,这个协议就是NSCoding协议,我们可以先来看一下NSCoding中的内容:
1 2 3 4 5 6 |
|
这个协议非常简单,一个init的归档方法,一个encode的解归档方法,NSCoder就是归档对象。原则上说,无论是什么数据类型的对象,系统的或者是我们自定义的,都可以通过实现这个协议中的方法来支持归档操作。
2、几种归档与解归档的应用
(1)通过类方法来对rootKey进行归档
这种方式,我个人理解,很类似于NSUserDefaults中的standardUserDefaults,只是后者是系统为我们创建的一个默认plist文件,而rootKey是系统为我们创建的一个默认的归档键值。说起来比较复杂,举个例子就十分清晰了:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上面的示例是对字符串类型进行的归档,是对单一的数据对象进行的归档,当然,这里的对象是支持数组、字典等集合的,但集合其中的对象,也必须全部支持归档操作。
(2)通过构造新的archiver对象,对多个对象进行归档
除了上面的类方法,我们还可以自己构造一个归档对象,来对多种不同的对象进行归档:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
结果如下:
(3)进行自定义对象的归档
上面介绍中有提到,原则上,任何遵守了NSCoding协议的类都可以进行归档操作,那么对于我们自定义的对象,我们该如何来做呢?
首先,我们新建一个类:
仿照上面的例子,我们写一个这样的类:
1 2 3 4 |
|
对其进行归档:
1 2 3 4 5 6 7 8 |
|
直接运行,程序会崩溃掉,打印如下:
可以看出,正是我们前边说过的,必须遵守归档协议的对象,才可以被归档,我们在MyObject类中实现如下两个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
添加了上面两个方法,我们自定义的对象就可以自由归档存取,并可以写入本地,非常cool吧。
三、设计可以归档存取的数据模型基类
1、动机与初衷
通过上面对归档的介绍,我们可以发现归档一个十分有潜力的应用:可以自由存取自定义的数据对象。这个特性的优势是毫无疑问的,除了可以使我们的数据用起来更加方便,无需多次解析数据外,安全性也更好。但是也带来了一个缺陷,每个类都需要实现NSCoding中的两个方法是十分繁琐的,并且类越复杂,这个步骤越繁琐,如果在之后的修改和优化中类做了改变,相应的方法也要做改变,这将增加很大的工作量并且埋下潜在bug的风险。
所以我们会想,能否设计一个这样的model基类,来使需要存储的model都继承于它,使我们的model不需要实现NSCoding方法的同时可以支持归档呢,通过runtime和OC语言特性的一些小技巧,我们是可以做到的。
2、基类模型的设计
我们新建一个BaseModel类,核心方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
通过这样的一个runtime机制,我们可以很方便的是新建的model继承于这个基类,无需其他处理直接支持归档,修改与优化都不受影响。