您的位置:首页 > 移动开发 > IOS开发

IOS持久化之NSKeyedArchiver,NSKeyedUnarchiver

2015-12-22 20:03 357 查看
归档与反归档需要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];
NSKeyedA
4000
rchiver *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属性,当归档和反归档时可以根据数据情况增加一些特殊处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: