基本的Objectiv-c物件,比如 NSString、NSArray、NSDictionary、NSSet、NSDate、NSNumber 和 NSData类型的物件,都可以用 之前提到过的方法 归档 和 恢复。但是 你 不能直接 用 这样的方法 对AddressBook类型的物件 进行归档。假如 我们 硬要这样 做的话,就像 这样:
你 会收到 这样的消息:
从这些错误信息中 我们 可以发现 系统 试图 对AddressBook类型的物件 采取 encodeWithCoder:这项措施,却发现 没有 一项叫encodeWithCoder:的措施 适用于 AddressBook类型的物件。
如果 要对上面列举的类型以外的物件 进行归档,我们 必须告诉 系统 如何归档,也就是 编码 以及 如何解档,也就是 解码。我们 使AddressBook 和 AddressCard这两类物件 遵循 <NSCoding>协议。根据<NSCoding>这项协议,我们 必须编写 encodeWithCoder: 和 initWithCoder:这两项措施,并 使 之 适用于 AddressBook 和 AddressCard这两类物件。
我们 每次对 某个物件 进行归档时 archiveRootObject:toFile:这项措施 都会对 需要归档的物件 采取 encodeWithCoder:这项措施。同样 解档的时候 也会采取 initWithCoder:这项措施。
一般来说 encodeWithCoder:这项措施 是 对你希望保存的物件所包含的变量 进行 归档的。对于 基本的objective-c物件 我们 可以采取 encodeObject:forKey:这项措施。而 对于 基本的c语言数据类型 我们 可以采取 下列的措施 进行 归档 和 解档:
编码 | 解码 |
encodeBool:forKey: | decodeBool:forKey: |
encodeInt:forKey: | decodeInt:forKey: |
encodeInt32:forKey: | decodeInt32:forKey: |
encodeInt64:forKey: | decodeInt64:forKey: |
encodeFloat:forKey: | decodeFloat:forKey: |
encodeDouble:forKey: | decodeDouble:forKey: |
对objective-c中的基本物件 归档时 采取 encodeObject:forKey:这项措施,而 解档时 刚好 相反,我们 要采取 decodeObject:forKey:这项措施。
接下来 我们 需要 在AddressCard这类物件的实施文件中 添加 encodeWithCoder: 和 initWithCoder:这两项措施:
在encodeWithCoder:这项措施当中 参数encoder 是 一个NSCoder类型的物件。由于 AddressCard这类物件 包含 在NSObject这类物件当中,你 不用担心 如何对各个AddressCard类型的物件中继承自NSObject这类物件的变量 进行编码。如果 你 知道 包含AddressCard这类物件的物件类型,比如 这里的NSObject这类物件, 遵循 <NSCoding>协议,那么 你 可以在encodeWithCoder:这项措施当中 对其实施对象 采取 适用于NSObject这类物件的encodeWithCoder:这项措施:
每个AddressCard类型的物件 都包含 name 和 email两个变量。由于 他们 都是 NSString类型的物件,我们 可以对他们 采取 encodeObject:forKey:这项措施 进行编码。
encodeObject:forKey:这项措施 不但 将 物件 进行编码 而且 给 这个物件 分配 一个特定的关键字。我们 可以根据物件所对应的关键字 将 物件 读取出来。编码时 给物件的关键字 是 随记的,只要 你 在读取 物件时 使用 完全相同的关键字 就可以了。唯一可能发生冲突的情况 就是 如果 一个物件所属的类型 包含 在另一个物件所属的类型当中,而 这两个物件 却有 相同的关键字。为了 防止 冲突的发生,我们 可以在关键字前面 加上 物件所属类型的名称。
解码的过程 刚好 相反。传递给initWithCoder:这项措施的参数 是 一个NSCoder类型的物件,存储 在变量decoder当中。你 不需要考虑 这个参数,只是记住 这个参数 可以得到 你想从归档中提取的物件的信息。
同样 由于 AddressCard这类物件 包含 在NSObject这类物件当中,你 同样 不需要担心 如何对各个AddressCard类型物件中继承自NSObject这类物件的变量 进行编码。如果 你 知道 NSObject这类物件 遵循 <NSCoding>这项协议,你 可以对initWithCoder:这项措施的实施对象 采取 适用于NSObject这类物件的措施initWithCoder:,就像 这样:
与 AddressCard这类物件 类似,我们 需要编写 适用于AddressBook这类物件的编码 和 解码措施。AddressBook这类物件的接口文件中 唯一需要修改的一行 就是 @interface这行,我们 需要把 这行语句 修改成 这样:
使 AddressBook这类物件 遵循 <NSCoding>这项协议。
AddressBook这类物件的实施部分 包含了 encodeWithCoder: 和 initWithCoder:这两项措施的具体内容:
我们 通过下面的程序 来检查 适用于AddressCard 和 AddressBook这两类物件的两项措施encodeWithCoder: 和 initWithCoder: 是否正常 工作:
这个程序 先创建了 一个地址簿,然后 将 其 归档 到文件addressbook.archive当中。你 可以在encodeWithCoder: 和 initWithCoder:这两项措施中 调用 NSLog()这个函数 来验证 这两项措施 是否得到了 执行。
下面的程序 展示了 如何将 归档文件 读取 到内存,并且 “组装成” 一个完好的AddressBook类型的物件:
运行 这个程序,可以得到 这样的结果:
1
2
3
4
5
6
|
2012-06-11 15:53:56.028 Sample[1802:707] ========Zijin's Address Book的内容========
2012-06-11 15:53:56.034 Sample[1802:707] Julia Kochan jewls337@axlc.com
2012-06-11 15:53:56.036 Sample[1802:707] Tony Iannino tony.iannino@techfitness.com
2012-06-11 15:53:56.037 Sample[1802:707] Stephen Kochan steve@steve_kochan.com
2012-06-11 15:53:56.037 Sample[1802:707] Jamie Baker jbaker@hitmail.com
2012-06-11 15:53:56.038 Sample[1802:707] =========================================
|