NSCoding

引用
iPhone开发应用中的Archiving NSCoder是本文要介绍的内容,举例我们创建保存一个nib文件,Interface Builder把对象写入到nib文件就是这样的arching过程,来看内容。

iPhone开发应用之Archiving NSCoder教程是本文要介绍的内容,一个面向对象程序在运行的时候,一般都创建了一个复杂的对象关系图,经常需要把这样一个复杂的对象关系图表示成字节流.这样的过程我们叫做Archiving 如图10.1, 

这个字节流可以在网络中传送,也可以写入到文件中. 例如,我们创建保存一个nib文件,Interface Builder把对象写入到nib文件就是这样的arching过程(对于Java,这个过程叫serialization)。 
 
而当从字节流中重新恢复对象关系图的过程叫做unarchive. 例如,当程序启动是,将会从nib文件中unarchive对象虽然对象包含成员变量和方法.但是只有成员变量和类名会被archive. 换句话说,data会被archive,而code不会. 所以,如果程序A archive对象,而程序B unarchive对象.那么程序A和B都要保证包含了class所连接的code. 举个例子,在nib文件中,你使用到了Appkit framework 的NSWindow和NSButton对象.那么如果我们的程序没有连接Appkit framework,那么我们就没有办法生成NSWindow和NSButton对象,因为archive中只包含了data,而没有code 

有一个洗发水的广告是这样说得:”我告诉了我的两个朋友,而他们各自又告诉了自己的两个朋友,这样一传十,十传百..”寓意就是,你告诉了你的朋友,最后所有的人都开始使用这个洗发水了. 对象archiving的工作方式和这差不多. 你archiving一个root对象. 它archiving自己相关联的对象,那些相关联的对象也会archiving自己相关联的对象,依次类推,所有相关的对象都被archiving了 

archiving由2步来完成. 1,我们需要告知我们的对象要怎么样来archive. 2. 我们需要激发archiving动作发生 

Objective-C语言有一个机制叫protocol, 就像java中的interface一样. 一个protocol声明了一系列方法.但你的类实现一个protocol,那么就预定了,你的类需要实现protocol中声明的所有方法 

NSCoder 和NSCoding 

NSCoding是一个protocol. 如果你的类实现了NSCoding.那么就要实现这些方法 

– (id)initWithCoder:(NSCoder *)coder;  
– (void)encodeWithCoder:(NSCoder *)coder; 
NSCoder是archivie 字节流的抽象类.我们可以实现把数据写入一个coder,也可以从coder中读取我们写入的数据. 我们对象的方法initWithCoder:就是从一个coder从读取数据,然后把数据赋给成员变量. 方法encodeWithCoder: 则是把成员变量的值写入到coder中. 在这一章中,我们会在Person类中实现这两个方法 

NSCoder是一个抽象类,我们不会直接使用它来创建对象. 相反,我们会使用从它继承来的子类. 也就是我们使用 NSKeyedUnarchiver类来从字节流中读取数据,而使用NSKeyedArchiver类来把对象写入到字节流 

Encoding 

NSCoder包含了很多方法, 不过大部分人会发现只会使用到其中很少的一部分. 下面是当要archivie数据时用到的一些常用方法 

– (void)encodeObject:(id)anObject forKey:(NSString *)aKey 
这个方法把anObject对象写入到coder中,并把它和aKey关联起来[下次使用aKey从coder中可以再把anObject读取出来] 这会是anObject的方法encodeWithCodr得到调用(还记得上面那个洗发水广告把.就是这样传下去的) 

对于C的基本类型(如int float).NSCoder使用下面方法 

– (void)encodeBool:(BOOL)boolv forKey:(NSString *)key  
– (void)encodeDouble:(double)realv forKey:(NSString *)key  
– (void)encodeFloat:(float)realv forKey:(NSString *)key  
– (void)encodeInt:(int)intv forKey:(NSString *)key 
添加encoing方法到Person类中. 

– (void)encodeWithCoder:(NSCoder *)coder  
{  
    [super encodeWithCoder:coder];  
    [coder encodeObject:personName forKey:@”personName”];  
    [coder encodeFloat:expectedRaise forKey:@”expectedRaise”];  

这里调用了父类的encodeWithCoder,使得父类有机会把自己的变量写入到coder中. 因此,类继承树中的类只会把自己的成员变量写入到coder-不会包含父类的成员变量 

Decoding 

从coder中decoding数据,我们使用这些方法 

– (id)decodeObjectForKey:(NSString *)aKey  
– (BOOL)decodeBoolForKey:(NSString *)key  
– (double)decodeDoubleForKey:(NSString *)key  
– (float)decodeFloatForKey:(NSString *)key  
– (int)decodeIntForKey:(NSString *)key 
如果因为某些原因, 字节流中没有和aKey关联的数据,那么我们会得到0值. 例如,对象没有把key foo 关联一个float数据写入coder,那么在使用foo key来读取这个float数据,coder会返回0.0 . 如果key foo关联的是一个对象数据[使用方法encodeWithCoder 写入],那么读取时coder返回nil 

添加decoding到Person类中 

– (id)initWithCoder:(NSCoder *)coder  
{  
   [super init];  
   personName = [[coder decodeObjectForKey:@”personName”] retain];  
   expectedRaise = [coder decodeFloatForKey:@”expectedRaise”];  
   return self;  

我们没有调用父类的initWithCoder, 那是因为NSObject没有实现它. 如过Person类的父类实现了NSCoding协议,那么这个方法应该这样写 

– (id)initWithCoder:(NSCoder *)coder  
{  
  [super initWithCoder:coder];  
  personName = [[coder decodeObjectForKey:@”personName”] retain];  
  expectedRaise = [coder decodeFloatForKey:@”expectedRaise”];  
  return self;  

你可以会说”在第3章中, designated initializer会完成所有的init工作然后在调用父类的 designated initializer, 也就是说类的其他initializer 方法都会调用designated initializer,Person类有designated initializer- init. 可以这个新加入的initializer方法并没有调用init方法阿?” 不错, 你是对的, initWithCoer: 是这个规则的一个特例. 

好了.我们实现了NSCoding协议的方法.现在让Person类实现NSCoding protocol. 我们来编辑Person.h文件. 

@interface Person : NSObject <NSCoding> { 
现在编译我们的工程. 你也可以运行程序看看.虽然Person类可以encode自己了.不过我们没有地方让它这么做.所以程序看上去没什么变化. 
原文地址:http://mobile.51cto.com/iphone-282203.htm

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s