打造强大的BaseModel(3):让Model实现自动归档

本文是「打造强大的BaseModel」的篇三篇,第一篇文章请见此:让Model自我描述 。第二篇文章请见此:让Model自动转换。相对于让Model实现自我描述和自动转换,让Model实现自动归档会难一点(事实后来我发现一点也不难)。我相信能够好好看完这三篇文章的人,绝对是有大收获的。

什么是iOS的归档

归档–NSKeyedArchiver,是iOS开发中基本的数据存储方式之一,和其他的数据存储方式相比,归档不仅能够存储任意类型的数据,而且使用起来也很简单。归档能将数据处理成NSData的形式,所以很容易以文件的形式保存在APP的沙盒中,而解归和归档相反,它是将保存在APP沙盒的归档文件逆归档,转换成归档前的状态。

传统的iOS归档方式

要想让一个自定义对象可以使用归档,必须要让其符合NSCoding协议,

上面的代码是iOS中NSCoding协议的定义。里面包含两个方法,其中一个是构造器。第一个方法

就是归档方法,它是为了告诉NSKeyedArchiver对象如何将数据归档成文件的。第二个方法(构造器)

就是解档方法了。它是告诉NSKeyedUnArchiver是如何将归档好的对象解档成原来的数据的
下面来看看传统的iOS归档方式,先定义一个类,让其符合NSCoding协议

我们需要在正确地重写这两个方法。这里面最需要注意的点有两个,一是不要把数据类型搞错。二是key名不要弄错了。然后下面开始测试

可见经过归档再解档后的数据又恢复了原样。这里需要说明一下的是,一般是需要把归档后的文件保存在APP的沙盒目录内的,需要使用时再取出来解档。这里为了测试方便就不这么做了。

传统的iOS归档方式的弊端

相信大家很容易看出使用传统的iOS归档方式的不足之处,还是和以前一样,需要写太多的重复啰嗦代码了。目前对于Objc语言来说,有一个代码生成器(Accessorizer,见Accessorize)可以使用,只需要把所有属性放进去,就可以生成所有属性的归档解档方法。遗憾的是Swift目前还没有这种工具可以用(或者有了但是我不知道),只有老实的让每个Model符合NSCoding协议,再写出每个属性的归档&解档方法。其中最让人疼的是有些属性还需要强制转换。而一般情况下一个项目的Model数都超过了两位数,虽然不一定每个Model都需要归档功能,但是如果一个类里面属性太多的话,写起来会让人很郁闷的。

使用RunTime实现自动归档

如果读者看了我先前的两篇–打造强大的BaseModel文章,脑子了应该可以很快构思出使用RunTime和KVC来实现自动归档的思路。先用RunTime获取Model中所有属性名,再用KVC获取每一个属性的值。再调用encodeWithCoder就能实现归档了。嗯,这种想法不错,下面直接写代码吧。

还是和以前一样,先写一个返回该类所有属性名的方法

和先前一样,利用Objc运行时的一系列方法可以从该类获取所有的属性名,下面是测试

下面来让GrandModel实现NSCoding协议,注意,实现NSCoding协议不能使用extension,因为指定构造器不能声明在extension中

没想到这么快就写好了,看起来也不难嘛,但是实际上这里这里存在一个显而易见的问题,就是归档方法中需要根据属性的类型调用不同的encode(属性类型)方法,本文的第一个例子里很清楚,对于Int类型的属性,需要调用aCoder.encodeInteger方法,Float和Double也不一样。如果统一使用 aCoder.encodeObject方法,就会造成数据类型丢失,

测试使用RunTime实现自动归档是否有效

这里可以测试一下。还是用文章开头的例子的哪个类,只不过需要去掉里面其他所有的方法只保留属性,并且添加了一些属性用来测试

实际上测试结果出乎我意料之外,非常完美,所有属性都成功地归档保存下来,解档后数据没有出现丢失的情况。对此我的分析是:这一切都是KVC的功劳。因为KVC取出的属性都是为AnyObject?类型,那么归档也就可以很方便地调用aCoder.encodeObject这个方法,所以数据以AnyObject类型保存。取出来时正好相反,用aDecoder.decodeObjectForKey这个角档方法取出来的数据类型都是AnyObject?类型的。然后KVC在组属性赋值并不需要知道每个属性是什么样的数据类型,都可以正确地赋值。难道事情就这样解决了吗?我们来看看下个测试用例

结果比预料中好了很多,nil的属性都可以正确打印出来。但是和以前一样,demoFloat:Float?这个属性又丢失了,这是很正常的,因为Objc不支持这种数据类型。读过我这系列文章的读者都可以明白。

那么如果属性类型是其他对象,或者是Array和字典类型呢?自动归档还能正常工作吗?答案是肯定的,只要该对象(Array或者Dict里保存的对象)都继承于GrandModel,都可以实现自动归档解档。

结果完全符合预期。

总结

让Model自动归档是iOS Runtime和KVC强大威力的又一次体现。这个组合就像一把锋利的尖刀,可以准确高效地解决问题,避免写很多重复的代码。缺点就是效率比正常代码要低一点,但是我认为这完全是可以接受的。这三篇文章所有的相关代码都可以在我的Github里面找到GrandModel,希望读者能给个Star。

1 5 收藏 2 评论

关于作者:ButterFly

简介还没来得及写 :) 个人主页 · 我的文章 · 1

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部