前幾篇文章說到了OC中的Foundation框架:http://blog.csdn.net/jiangwei0910410003/article/details/41852835,今天咱們來看一下OC中的一個重要知識點:歸檔java
OC中的歸檔就是將對象寫入到一個文件中,Java中的ObjectInputStream和ObjectOutputStream來進行操做的。固然在操做的這些對象都是須要實現一個接口:Serializable,一樣的OC中操做的對象也是須要實現一個協議的,後面會說到。app
1、已有類型的歸檔和解檔框架
首先來看一個簡單的例子:iphone
// // main.m // 33_ObjectToFile // // Created by jiangwei on 14-10-13. // Copyright (c) 2014年 jiangwei. All rights reserved. // #import <Foundation/Foundation.h> //歸檔:將一個對象寫到文件中 int main(int argc, const char * argv[]) { @autoreleasepool { //第一種形式:歸檔對象 //對象----》文件 /* NSArray *array = [NSArray arrayWithObjects:@"zhang",@"wangwu",@"lisi",nil]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [NSKeyedArchiver archiveRootObject:array toFile:filePath]; if(success){ NSLog(@"保存成功"); } */ /*解歸檔 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; id array = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@",array); */ //第二種方式 //第一種方式的缺陷是一個對象歸檔成一個文件 //可是第二種方式,多個對象能夠歸檔成一個文件 /* NSArray *array = [NSArray arrayWithObjects:@"zhangsan",@"lisi", nil]; NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //編碼 [archiver encodeObject:array forKey:@"array"]; [archiver encodeInt:100 forKey:@"scope"]; [archiver encodeObject:@"jack" forKey:@"name"]; //完成編碼,將上面的歸檔數據填充到data中,此時data中已經存儲了歸檔對象的數據 [archiver finishEncoding]; [archiver release]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [data writeToFile:filePath atomically:YES]; if(success){ NSLog(@"歸檔成功"); } */ NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; //讀取歸檔數據 NSData *data = [[NSData alloc] initWithContentsOfFile:filePath]; //建立解歸檔對象,對data中的數據進行解歸檔 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; //解歸檔 NSArray *array = [unarchiver decodeObjectForKey:@"array"]; NSLog(@"%@",array); int value = [unarchiver decodeObjectForKey:@"scope"]; NSLog(@"%d",value); } return 0; }
//第一種形式:歸檔對象 //對象----》文件 NSArray *array = [NSArray arrayWithObjects:@"zhang",@"wangwu",@"lisi",nil]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [NSKeyedArchiver archiveRootObject:array toFile:filePath]; if(success){ NSLog(@"保存成功"); }咱們這裏將一個NSArray對象寫入到一個文件中。
這裏說到了建立一個文件的方法:編碼
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"];
咱們能夠打印一下filePath的值:atom
NSHomeDirectory()返回的就是當前用戶路徑加密
咱們查看一下array.src的內容:spa
咱們看到內容是亂的,可是咱們貌似仍是能看到一點,好比wangwu/lisi等字眼,說明在歸檔的時候並無深刻的加密。.net
//解歸檔 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; id array = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@",array);解檔也是很簡單的,就是返回一個對象,不過這裏用了id類型的,由於讀出來也不肯定是哪一種類型的。
三、對多個對象進行歸檔到一個文件code
//第二種方式 //第一種方式的缺陷是一個對象歸檔成一個文件 //可是第二種方式,多個對象能夠歸檔成一個文件 NSArray *array = [NSArray arrayWithObjects:@"zhangsan",@"lisi", nil]; NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //編碼 [archiver encodeObject:array forKey:@"array"]; [archiver encodeInt:100 forKey:@"scope"]; [archiver encodeObject:@"jack" forKey:@"name"]; //完成編碼,將上面的歸檔數據填充到data中,此時data中已經存儲了歸檔對象的數據 [archiver finishEncoding]; [archiver release]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [data writeToFile:filePath atomically:YES]; if(success){ NSLog(@"歸檔成功"); }多個對象歸檔的話,這裏要用到一個類: NSMutableData和NSData,他們兩的區別很簡單,一個是可變的,一個是不可變的。而後這裏還建立了一個歸檔器:NSKeyedArchiver,這個類負責進行指定類型的編碼操做,而後將數據填充到NSMutableData類。歸檔的時候對每一個類型對象用一個key進行對應,這個NSData和NSDirctionary很相似了。
四、對多個對象進行解檔操做
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; //讀取歸檔數據 NSData *data = [[NSData alloc] initWithContentsOfFile:filePath]; //建立解歸檔對象,對data中的數據進行解歸檔 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; //解歸檔 NSArray *array = [unarchiver decodeObjectForKey:@"array"]; NSLog(@"%@",array); int value = [unarchiver decodeObjectForKey:@"scope"]; NSLog(@"%d",value);咱們能夠將文件解檔出一個NSData對象,而後能夠經過key去獲取指定的類型對象
2、自定義類型的歸檔和解檔
上面說到了已有類型的歸檔和解檔,下面來看一下自定義類型的歸檔和解檔操做,在開始的時候也說了,若是自定義的類型能夠進行歸檔和解檔的話,必須實現一個協議:NSCoding
很少說了,下面來直接看代碼解釋:
Person.h
// // Person.h // 34_ArchiveProtocol // // Created by jiangwei on 14-10-13. // Copyright (c) 2014年 jiangwei. All rights reserved. // #import <Foundation/Foundation.h> //類只有實現NSCoding協議才能歸檔 @interface Person : NSObject<NSCoding> @property(nonatomic,copy)NSString *name; @property(nonatomic,assign)NSInteger age; @property(nonatomic,retain)NSArray *apples; - (NSString *)description; @end這裏自定義了一個Person類型,實現了NSCoding協議,而後他有三個屬性,這裏咱們看到有新的方法去定義屬性,這個後面說到內存管理的時候在詳細說明。
Person.m
// // Person.m // 34_ArchiveProtocol // // Created by jiangwei on 14-10-13. // Copyright (c) 2014年 jiangwei. All rights reserved. // #import "Person.h" @implementation Person //解歸檔的時候調用 //也是一個初始化方法 - (id)initWithCoder:(NSCoder *)aDecoder{ NSLog(@"initWithCoder"); self = [super init]; if(self != nil){ /* _name = [aDecoder decodeObjectForKey:@"name"]; _age = [aDecoder decodeObjectForKey:@"age"]; _apples = [aDecoder decodeObjectForKey:@"apples"]; */ //通常咱們將key定義成宏,這樣就不會出錯 _name = [[aDecoder decodeObjectForKey:@"name"] copy]; self.age = [aDecoder decodeObjectForKey:@"age"]; self.apples = [aDecoder decodeObjectForKey:@"apples"]; } return self; } //歸檔時調用此方法 - (void)encodeWithCoder:(NSCoder *)aCoder{ NSLog(@"encodeWithCoder"); [aCoder encodeObject:_name forKey:@"name"];//通常key和屬性名是取同樣的 [aCoder encodeInteger:_age forKey:@"age"]; [aCoder encodeObject:_apples forKey:@"apples"]; } - (NSString *)description{ NSString *string = [NSString stringWithFormat:@"name=%@,age=%d,apples=%@",_name,_age,_apples]; return string; } @end在Person.m文件中,咱們須要實現協議中的兩個方法:
initWithCoder
encodeWithCoder
這兩個方法一個是用於歸檔操做時會調用的方法,還有一個是用於解檔操做時會調用的方法一、解檔的時候用到的方法
- (id)initWithCoder:(NSCoder *)aDecoder{ NSLog(@"initWithCoder"); self = [super init]; if(self != nil){ /* _name = [aDecoder decodeObjectForKey:@"name"]; _age = [aDecoder decodeObjectForKey:@"age"]; _apples = [aDecoder decodeObjectForKey:@"apples"]; */ //通常咱們將key定義成宏,這樣就不會出錯 _name = [[aDecoder decodeObjectForKey:@"name"] copy]; self.age = [aDecoder decodeObjectForKey:@"age"]; self.apples = [aDecoder decodeObjectForKey:@"apples"]; } return self; }這個是一個初始化的方法,同時他也是一個解檔操做時會調用的方法,因此在這裏咱們既要寫一下初始化方法的特定代碼,還要寫上解檔的代碼,這裏主要看解檔的代碼
其實很簡單,就是對屬性從新寫一下值,而後對每一個屬性指定一個key就能夠了。這個有點相似於Android中的Parcel
(這裏咱們看到,在解檔name屬性的時候,用到了copy的一個方法,這個在後面會說到,有淺拷貝和深拷貝之分)
二、歸檔的時候用到的方法
//歸檔時調用此方法 - (void)encodeWithCoder:(NSCoder *)aCoder{ NSLog(@"encodeWithCoder"); [aCoder encodeObject:_name forKey:@"name"];//通常key和屬性名是取同樣的 [aCoder encodeInteger:_age forKey:@"age"]; [aCoder encodeObject:_apples forKey:@"apples"]; }歸檔和解檔的操做正好相反的,可是要注意的是:他們屬性的key必定要保持一致
三、重寫description方法
- (NSString *)description{ NSString *string = [NSString stringWithFormat:@"name=%@,age=%d,apples=%@",_name,_age,_apples]; return string; }在以前的文章中我說道過,咱們在使用NSLog方法打印對象的值的時候,實際上是調用對象的description方法,而這個方法是NSObject類中的,咱們能夠重寫他,這樣咱們就能夠打印咱們想要的信息了。和Java中的toString方法同樣。
下面就來看一下使用方法了
main.m
// // main.m // 34_ArchiveProtocol // // Created by jiangwei on 14-10-13. // Copyright (c) 2014年 jiangwei. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; p.name = @"張三"; p.age = 20; p.apples = @[@"iphone",@"ipad"]; //歸檔 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"person.archiver"]; BOOL success = [NSKeyedArchiver archiveRootObject:p toFile:filePath]; if(success){ NSLog(@"歸檔成功"); } //解歸檔 Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@",person); } return 0; }咱們能夠看到,使用起來是很簡單的和上面的方式同樣,運行結果:
看到了,咱們自定義的description方法,打印了咱們本身想要的結果~~
總結
這一篇文章咱們就說了OC中的歸檔和解檔的相關概念和操做,其實說白了就是將對象寫入到文件,和從文件中讀取對象。