oc歸檔與解檔(序列化和反序列化)

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;

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粱锐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子扛邑,更是在濱河造成了極大的恐慌怜浅,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔬崩,死亡現(xiàn)場離奇詭異恶座,居然都是意外死亡,警方通過查閱死者的電腦和手機沥阳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門跨琳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桐罕,你說我怎么就攤上這事脉让。” “怎么了功炮?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵溅潜,是天一觀的道長。 經(jīng)常有香客問我薪伏,道長滚澜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任嫁怀,我火速辦了婚禮设捐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塘淑。我一直安慰自己挡育,他們只是感情好,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布朴爬。 她就那樣靜靜地躺著即寒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪召噩。 梳的紋絲不亂的頭發(fā)上母赵,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音具滴,去河邊找鬼凹嘲。 笑死,一個胖子當著我的面吹牛构韵,可吹牛的內(nèi)容都是我干的周蹭。 我是一名探鬼主播趋艘,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凶朗!你這毒婦竟也來了瓷胧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤棚愤,失蹤者是張志新(化名)和其女友劉穎搓萧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宛畦,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡哼绑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年屈暗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旋圆。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡顽馋,死狀恐怖见芹,靈堂內(nèi)的尸體忽然破棺而出啸蜜,到底是詐尸還是另有隱情江兢,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布读规,位于F島的核電站,受9級特大地震影響燃少,放射性物質(zhì)發(fā)生泄漏束亏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一阵具、第九天 我趴在偏房一處隱蔽的房頂上張望碍遍。 院中可真熱鬧,春花似錦阳液、人聲如沸怕敬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽东跪。三九已至,卻和暖如春鹰溜,著一層夾襖步出監(jiān)牢的瞬間虽填,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工曹动, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斋日,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓墓陈,卻偏偏與公主長得像恶守,于是被迫代替她去往敵國和親第献。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容