Foundation框架的歸檔功能
將對象存儲轉(zhuǎn)換為二進制序列的過程成為歸檔诉位、打包或編碼骑脱,逆變換稱為解檔、解碼或?qū)ο筮€原苍糠。
可以使用NSKeyedArchiver和NSKeyedUnarchiver完成對象的歸檔和解檔操作叁丧,而他們都是抽象類NSCoder的子類。
所有可以歸檔的對象都必須要適用于協(xié)議NSCoding岳瞭。協(xié)議NSCoding在Foundation/NSObject.h中定義歹袁,NSObject自身并不采用該協(xié)議。NSString寝优、NSDictionary等Foundation框架的主要類都適用協(xié)議NSCoding。
協(xié)議NSCoding按照如下方式聲明:
@protocolNSCoding
-(void)encodeWithCoder:(NSCoder*)coder
-(id)initWithCoder:(NSCoder*)coder
歸檔方法的定義
協(xié)議NSCoding中枫耳,函數(shù)encodeWithCoder:定義了歸檔自身的方法乏矾。
- (void)encodeWithCoder:(NSCoder *)coder
{
????[super encodeWithCoder:coder];
????//超類需要適用NSCoding協(xié)議
????[coder encodeObject:對象 forKey:關(guān)鍵詞字符串];
????[coder encodeInt:實數(shù)變量 forKey:關(guān)鍵詞字符串];
}
如果超類不適用協(xié)議NSCoding,則不能調(diào)用encodeWithCoder:方法迁杨。
類自身對包含的實例變量歸檔钻心。在類沒有自己的實例變量且超類中定義了方法encodeWithCoder:的情況下,該方法就不需要在定義了铅协。
通過使用NSString字符串作為鍵值捷沸,可以指定歸檔解檔的內(nèi)容。讓某個類實例歸檔時狐史,它的實例變量必須指定成不同的鍵值痒给。在單個對象內(nèi)部,如果超類使用了一個鍵值骏全,那么子類中就不能使用該鍵值苍柏。鍵值只需在同一個類內(nèi)區(qū)分出來即可,不同的類可使用相同的鍵值姜贡。
當對象圖有閉環(huán)時试吁,同一個對象會重復要求歸檔,實際上已歸檔的對象是不用重復歸檔的楼咳。
解檔方法的定義
- (instancetype)initWithCoder:(NSCoder *)coder{
????self= [superinitWithCoder:coder];
????//超類不適應(yīng)于協(xié)議NSCoding時熄捍,????
????//建議使用 self = [super init];
if (self) {
????self.name= [coder decodeObjectForKey: 鍵值];
????self.age= [coder decodeIntForKey: 鍵值];? ?
?????}
????returnself;
}
歸檔示例程序:
main.m
#import? <Foundation/Foundation.h>
#import"Person.h"
int main(intargc,constchar* argv[])?{? ??
????@autoreleasepool {? ? ? ??
????????Person * p = [[Person alloc] init];? ? ? ?
?????????p.name= @"lu";? ? ? ?
?????????p.age=18;? ? ? ?
?????????p.weight=100.0;
????????BOOLisSuccess = [NSKeyedArchiver archiveRootObject:p toFile:@"/Users/lu/Desktop/test.plist"];if(isSuccess) {NSLog(@"歸檔成功");? ? ?
?????????? }else{
????????????????NSLog(@"歸檔失敗");? ? ??
? ????????}??
????? }
????return0;
}
解檔示例程序:
main.m
intmain(intargc,constchar* argv[]) {? ??
????@autoreleasepool {
????????????//解檔????
????????????Person * p = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/lu/Desktop/test.plist"];
????????????NSLog(@"%@",p.name);
????????????NSLog(@"%d",p.age);
????????????NSLog(@"%f",p.weight);? ??
????????}
????????return0;
}
若類中實例變量為其他類對象,則還需要在其他類中實現(xiàn)encodeWithCoder:和initWithCoder:方法母怜。
示例程序:
Dog.m
#import"Dog.h"?
@implementation Dog
- (void)encodeWithCoder:(NSCoder *)coder{?
? ? ?[coder encodeObject:self.nameforKey:@"name"];? ?
?????[coder encodeInt:self.ageforKey:@"age"];}
- (instancetype)initWithCoder:(NSCoder *)coder{
????self= [superinit];
????if (self) {
????????self.name= [coder decodeObjectForKey:@"name"];self.age= [coder decodeIntForKey:@"age"];? ? }
????????return self;
}
@end
student.m
#import"Student.h"
#import"Dog.h"
@implementationStudent
//歸檔
- (void)encodeWithCoder:(NSCoder *)coder{??
?[coder encodeObject:self.nameforKey:@"name"];? ?
?[coder encodeInt:self.scoreforKey:@"score"];??
?[coder encodeInt:self.numberforKey:@"number"];?
? [coder encodeObject:self.dogforKey:@"dog"];}
//解檔
- (instancetype)initWithCoder:(NSCoder *)coder{
self = [superinit];
????if (self) {
????self.name= [coder decodeObjectForKey:@"name"];
????self.score= [coder decodeIntForKey:@"score"];
????self.number= [coder decodeIntForKey:@"number"];
????self.dog= [coder decodeObjectForKey:@"dog"];??
? }
????return self;
}
@end
main.m
int main(intargc,constchar* argv[]) {?
?? @autoreleasepool {? ? ??
? ? ?Student * stu = [[Student alloc] init];? ? ? ??
????stu.name= @"di";? ? ? ?
?????stu.score=70;? ? ? ?
?????stu.number=20;? ? ??
? ????Dog * d = [[Dog alloc] init];? ? ? ?
?????d.name= @"Chen";? ? ?
? ? ? d.age=10;? ? ??
? ????stu.dog= d;
//歸檔
BOOL isSuccess = [NSKeyedArchiver archiveRootObject:stu toFile:@"/Users/lu/Desktop/Stu.txt"];if(isSuccess) {NSLog(@"Yes");? ? ?
?? }else{
????????NSLog(@"NO");? ??
? ? }
//解檔
????Student * stu3 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/lu/Desktop/Stu.txt"];NSLog(@"%@", stu3.name);
????NSLog(@"%d", stu3.score);
????NSLog(@"%d", stu3.number);
????NSLog(@"%@", stu3.dog.name);
????NSLog(@"%d", stu3.dog.age);??
????? }
????return0;?
?}
對多個對象進行歸檔余耽,可以先將多個對象存儲于NSArray、NSMutableArray糙申、NSDictionary或NSMutableDictionary中宾添,再進行歸檔船惨。
示例程序:
NSArray* stuArray = @[stu, stu1, stu2];
BOOLisSuccess = [NSKeyedArchiver archiveRootObject:stuArray toFile:@"/Users/lu/Desktop/stuArray.txt"];
if(isSuccess) {
????NSLog(@"Yes");? ? ? ??
}else{
????NSLog(@"NO");? ? ? ??
}
最后一種方式利用NSData對多個對象進行歸檔解檔
示例程序
main.m
#import
#import"Person.h"
int main(intargc,constchar* argv[]) {??
? @autoreleasepool {? ? ? ?
?????Person * p = [[Person alloc] init];? ??
? ? ?p.name= @"dou";??
? ? ?p.age=22;? ??
? ? ?p.weight=120.00;? ?
?? ? Person * p2 = [[Person alloc] init];?
? ? ? p2.name= @"dashu";??
? ? ? p2.age=24;??
? ? ? p2.weight=140.3;??
? ? ? NSMutableData * data = [NSMutableData data];//? ? ? ? 根據(jù)二進制流創(chuàng)建NSkeyedArchiver對象????
? ? ? NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
//? ? ? ? 對對象進行歸檔操作
????[archiver encodeObject:p forKey:@"person1"];? ??
? ? ?[archiver encodeObject:p2 forKey:@"person2"];
//? ? ? ? 結(jié)束歸檔
/*** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
歸檔如果沒有結(jié)束 finishEncoding就不會歸檔成功,產(chǎn)生文件無法打開? ? The data couldn't be read because it isn't in the correct format.
*/
[archiver finishEncoding];
BOOL isSuccess = [data writeToFile:@"/Users/lu/Desktop/Data.plist"atomically:YES];if(isSuccess) {
? ? ? ?NSLog(@"歸檔成功缕陕!");? ?
?? ? }else{
????????NSLog(@"歸檔失敗");? ? ??
? }
//解檔NSData * data = [NSData dataWithContentsOfFile:@"/Users/lu/Desktop/Data.plist"];? ? ? ? NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];? ? ??
? Person * p = [unarchiver decodeObjectForKey:@"person1"];? ? ?
? Person * p2 = [unarchiver decodeObjectForKey:@"person2"];
//結(jié)束解檔 解檔沒有finishDecoding無影響
// [unarchiver finishDecoding];
NSLog(@"%@", p.name);
NSLog(@"%d", p.age);NSLog(@"%f", p.weight);
NSLog(@"%@", p2.name);NSLog(@"%d", p2.age);NSLog(@"%f", p2.weight);? ?
?}
return0;
}