`
lizaochengwen
  • 浏览: 643783 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

iPhone开发应用之Archiving NSCoder教程(1)

阅读更多
引用
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
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics