IOS持久化之NSKeyedArchiver,NSKeyedUnarchiver

来源:互联网 发布:海岛奇兵21本升级数据 编辑:程序博客网 时间:2024/05/16 07:33

归档与反归档需要NSCoding协议的支持, 需要编解码的自定义对象的类也要支持该协议。

NSCoding协议:

- (void) encodeWithCoder : (NSCoder *) aCoder;

- (id) initWithCoder:(NSCoder *) aDecoder;


NSKeyedArchiver,NSKeyedUnarchiver类支持NSCoder协议:

- (void)encodeObject:(nullableid)objv forKey:(NSString *)key;

- (nullableid)decodeObjectForKey:(NSString *)key;


协议支持示例代码(user,childUser,teacher属性分别为类User,ChildUser,Teacher的对象,User,ChildUser和Teacher类均实现了NSCoding协议):

其中,如果encodeObject:forKey和deCodeObjectForKey的对象如果是自定义的类的话,则该自定义类也要实现NSCoding协议来支持对其编解码,如果是NSObject等类对象的话,这些类本身支持了编解码(NSObject支持编解码,但是不支持NSCoding协议,因此基类是NSObject不能调用基类的编解码方法)。encodeWithCode和initWithCoder方法中的归档与反归档的对象必须成对出现,否则持久化就会出错。注意这个方法中,如果父类也支持NSCoding协议,一般会调用基类的encodeWithCoder和initWithCoder方法。

<p class="p1"><span class="s1">- (</span><span class="s2">void</span><span class="s1">)encodeWithCoder:(</span><span class="s3">NSCoder</span><span class="s1"> *)aCoder{</span></p><p class="p2"><span class="s1"> </span><span class="s4" style="font-family: Menlo;">    [aCoder </span><span class="s1" style="font-family: Menlo;">encodeObject</span><span class="s4" style="font-family: Menlo;">:</span><span class="s1" style="font-family: Menlo;">_user</span><span class="s4" style="font-family: Menlo;"> </span><span class="s1" style="font-family: Menlo;">forKey</span><span class="s4" style="font-family: Menlo;">:</span><span class="s5" style="font-family: Menlo;">@"user"</span><span class="s4" style="font-family: Menlo;">];</span></p><p class="p3"><span class="s4">    [aCoder </span><span class="s1">encodeObject</span><span class="s4">:</span><span class="s1">_childUser</span><span class="s4"> </span><span class="s1">forKey</span><span class="s4">:</span><span class="s5">@"childUser"</span><span class="s4">];</span></p><p class="p3"><span class="s4">    [aCoder </span><span class="s1">encodeObject</span><span class="s4">:</span><span class="s1">_teacher</span><span class="s4"> </span><span class="s1">forKey</span><span class="s4">:</span><span class="s5">@"teacher"</span><span class="s4">];</span></p><p class="p1"><span class="s1">}</span></p><p class="p2"><span class="s1"></span></p><p class="p1"><span class="s1">- (</span><span class="s2">id</span><span class="s1">)initWithCoder:(</span><span class="s3">NSCoder</span><span class="s1"> *)aDecoder{</span></p><p class="p3"><span class="s4">    </span><span class="s1">_user</span><span class="s4"> = [ aDecoder </span><span class="s1">decodeObjectForKey</span><span class="s4">:</span><span class="s5">@"user"</span><span class="s4">];</span></p><p class="p3"><span class="s4">    </span><span class="s1">_childUser</span><span class="s4"> = [ aDecoder </span><span class="s1">decodeObjectForKey</span><span class="s4">:</span><span class="s5">@"childUser"</span><span class="s4">];</span></p><p class="p3"><span class="s4">    </span><span class="s1">_teacher</span><span class="s4"> = [aDecoder </span><span class="s1">decodeObjectForKey</span><span class="s4">:</span><span class="s5">@"teacher"</span><span class="s4">];</span></p><p class="p4"><span class="s4">    </span><span class="s1">return</span><span class="s4"> </span><span class="s1">self</span><span class="s4">;</span></p><p class="p1"><span class="s1">}</span></p>


ChildUser方法中的NSCoding协议支持如下,由于调用了super::encodeWithCoder,因此基类和派生类编辑码的键名不可以重名,如果重名,归档的话,后面的会覆盖前面的:

- (void)encodeWithCoder:(NSCoder *)aCoder{        [super encodeWithCoder:aCoder];    [aCoder encodeObject:_name2 forKey:@"name"];    return;}- (id)initWithCoder:(NSCoder *)aDecoder{        self = [super initWithCoder:aDecoder];        _name2 = [ aDecoder decodeObjectForKey:@"name"];    return self;}


调用方法:

    // 测试NSKeyedArchiver键名重名

    UserGroup *userGroup = [[UserGroupalloc] init];

    NSArray *pathArray =NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);

    NSString *fileDirectory = [pathArrayobjectAtIndex:0];

    NSString *filePath = [fileDirectorystringByAppendingPathComponent:@"test.txt"];

    //归档

    BOOL bSuccess = [NSKeyedArchiverarchiveRootObject:userGroup toFile: filePath];

    //反归档

    UserGroup *userGroup2 = [NSKeyedUnarchiverunarchiveObjectWithFile:filePath];

     开始测试时归档失败,是因为NSSearchPathForDirectoriesInDomains第二个参数设置为了NSLocalDomainMask,这个参数得到的目录,不是沙盒内部,没有写权限。


经测试,不同的对象内部的属性的键名重名是没有问题的,只有同一个对象中的基类和派生类属性编解码时键名不可重名(基类和派生类的property也不可重名)。

归档文件时也可以使用NSData辅助来实现,如下:
NSMutableData *tempData = [NSMutableData data];  NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:tempData];  [archiver encodeObject:userGroup forKey:@"root"];  <span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">//可以编、解码多个</span>[archiver finishEncoding];    if (![tempData writeToFile:dataFilePath atomically:YES]) {      NSLog(@"fail to archive data object");  }  

反归档:
NSData *tempData = [NSData dataWithContentsOfFile:dataFilePath];  if (tempData) {      // 通过解码恢复对象      NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:tempData];      UserGroup userGroup = <span style="margin: 0px; padding: 0px; border: none; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">[unarchiver decodeObjectForKey: @"root"</span><span style="margin: 0px; padding: 0px; border: none; font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">];  //可以编、解码多个</span>    [unarchiver finishDecoding];  

上述通过NSData方式操作数据可以实现深复制,如下:

NSData *tempData = [NSKeyedArchiver archivedDataWithRootObject:marray1];  marray2 = [NSKeyedUnarchiver unarchiveObjectWithData:tempData];  

userGroup归档后的文件内容如下:

bplist00‘89T$topX$objectsX$versionY$archiver—TrootÄ≠#$%+.3U$null‘TuserWteacherV$classYchildUserÄÄÄÄ“TnameÄÄ“X$classesZ$classname¢TUserXNSObjectTUser” !"YchildNameÄÄÄUuser2ZChilduser2“&*£'()YChildUserTUserXNSObjectYChildUser“,-ÄÄ“/2¢01WTeacherXNSObjectWTeacher“47¢56YUserGroupXNSObjectYUserGroup܆_NSKeyedArchiver(25:<JPY^fmwy{}Ñâãçíõ¶©Æ∑º√Õœ—”Ÿ‰È̘¸ (19>AKT^c:u
键名用的明文,键值和对象的类的信息经过了处理,具体结构不详。


NSKeyedArchiverDelegate, NSKeyedUnarchiverDelegate,归档和反归档代理,可以设置NSKeyedArchive和NSKeyedUnarchiver对象的delegate属性,当归档和反归档时可以根据数据情况增加一些特殊处理。


0 0
原创粉丝点击