IOS持久化之NSKeyedArchiver,NSKeyedUnarchiver

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

NSCoding协议:

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

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


NSKeyedArchiver,NSKeyedUnarchiver类支持NSCoder协议:

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

- (nullable id)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 = [[UserGroup alloc] init];

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

    NSString *fileDirectory = [pathArray objectAtIndex:0];

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

    //归档

    BOOL bSuccess = [NSKeyedArchiver archiveRootObject:userGroup toFile: filePath];

    //反归档

    UserGroup *userGroup2 = [NSKeyedUnarchiver unarchiveObjectWithFile: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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值