iOS 固化

在 iOS 中,有很多途径可以将对象写入磁盘,其中最重要的一种途径是“固化”(archiving):固化是将单个或多个对象从内存写入文件系统的过程。“解固”(unarchiving)是从文件读取对象并写回内存。

固化可以通过 NSCoder 实例来完成, NSCoder 实例本身就是一个数据容器,可以存放对象和对象的数据,一旦 NSCoder 收集齐所需的数据,就可以将其写入指定的文件系统中的文件。

不是所有对象都可以固化 - 只有遵守 NSCoding 协议的对象才可以。

NSCoding 协议有两个方法(都是必须的方法):encodeWithCoder:(固化用);initWithCoder(解固用)

一, 对象的固化

通过 NSKeyedArchiver 的类方法 archiveRootObject:toFile :可以将遵守 NSCoding 协议的对象写入文件。NSKeyedArchiver 是 NSCoder 的子类。

archiveRootObject:toFile: 方法的第一个参数是根对象(root Object);第二个参数是写入文件的路径

// 将传入的文件名加在目录后并返回
// archiverRootObject:toFile:方法会创建一个 NSKeyedArchiver 实例,然后向 allObjects  发送 encodeWithCoder 消息,并将新创建的 NSKeyedArchiver 对象作为参数传入。 固化数组时,数组中的对象也会被固化(前提是这些对象也遵守 NSCoding 协议)
 return [NSKeyedArchiver archiveRootObject:allObjects toFile:objectsPath]; 

如图:

在 encodeWithCoder 中,通过向 NSCoder 对象(这里是 NSKeyedArchiver 对象)发送 encodeObject:forkey: 消息,可以对对象的实例变量编码(encode)

- (void)encodeWithCoder:(NSCoder *)encoder
{
  // 根据变量名固化实例变量
  // 如果实例变量是对象,则该对象也会受到 encodeWithCoder: 消息
  [encoder encodeObject:objectName1 forkey:@"objectName1"];
  [encoder encodeObject:objectName2 forkey:@"objectName2"] 
  // 基本类型
  [encode encodeInt:int1 forkey:@"int1"];          
}

这类固化称为“有键固化”(keyed archiving),有键固化的工作机制与  NSMutableDictionary 非常类似:通过加入对象,并用同一个键取出对象,有键固化使用的键都是 NSString 实例,通常是需要编码的实例变量的变量名

如果传入 encodeWithCoder: 的实例对象是对象,那么该对象也会受到 encodeWithCoder:消息,所以固化是一个递归过程

二, 对象的解固

应用通过“解固”来载入固化后的对象,首先,程序会创建一个 NSCoder 实例,然后从文件系统读入数据,最后解固固化后的对象。

通过 NSKeyedUnarchiver 的类方法 unarchiveObjectWithFile: 可将数据从文件系统还原至内存。

NSKeyedUnarchiver 也是 NSCoder 的子类。 unarchiveObjectWithFile: 的参数是固化文件的路径,它会将相应的文件读入内存,然后开始一系列的解固过程

// 如果allObjects数组不存在,则从文件取之
// 注意,unarchiveObjectWithFile: 的返回值类型为 id
if(!allObjects)
{
  NSString *path= obejctsPath;
  allObjects = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];    
}

解固的根对象为 allObjects ,类型为NSMutaleArray,NSMutableArray 的 initWithCoder: 方法会向每个已固化对象发送 decodeObjectForKey: 消息,从而解码数组中的内容

- (id)initWithCoder:(NSCoder *)decoder
{
  self = [super init];
  if (self) {
     [self setObjectName1:[decoder decodeObjectForKey:@"objectName1"]];
      [self setObjectName2:[decoder decodeObjectForKey:@"objectName2"]];
      [self setint1:[decoder decodeIntForKey:@"int1"]] ; 
    }
      return self ;  
}    

 

 

posted @ 2013-08-20 15:46  Dayw  阅读(962)  评论(0编辑  收藏  举报