在平時的iOS開發中,咱們常常用到的數據持久化存儲方式大概主要有:NSUserDefaults(plist),文件,數據庫,歸檔。。前三種比較常常用到,第四種歸檔我我的感受用的仍是比較少的,偏偏由於用的比較少,可是仍是有地方要用到,因此今天再把歸檔解檔複習一遍吧。數據庫
1、什麼是歸檔:數組
對象歸檔是將對象以文件的形式保存到磁盤中(也稱爲序列化,持久化) ;使用的時候讀取該文件的保存路徑讀取文件的內容(也稱爲解檔,反序列化)。
框架
2、歸檔 與 plist存儲的區別:函數
3、歸檔的使用編碼
剛剛說到,只要是對象類型,均可以用歸檔的方式進行保存。atom
可是,只有實現了<NSCoding>協議的類型才能夠進行歸檔,因爲Foudation框架中的對象類型已經實現了NSCoding協議,因此能夠直接歸檔解檔,而咱們自定義的類型,則須要咱們手動去實現NSCoding協議。必須實現一下兩個方法:spa
//歸檔的時候調用的方法 - (void)encodeWithCoder:(NSCoder *)aCoder; //解歸檔的時候要調用的函數 - (id)initWithCoder:(NSCoder *)aDecoder;
1.對系統類的歸檔:code
第一種方式:單個對象的歸檔和解檔對象
//單個對象歸檔: NSArray *array1 = @[@"zhangsan",@"wangwu",@"lisi"]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [NSKeyedArchiver archiveRootObject:array1 toFile:filePath]; if (success) { NSLog(@"保存成功!"); } //單個對象解檔 id array2 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@",array2);
第二種方式:多個對象的歸檔和解檔blog
//多個對象歸檔: NSArray *array1 = @[@"zhangsan",@"wangwu",@"lisi"]; NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //編碼 [archiver encodeObject:array1 forKey:@"array"]; [archiver encodeInt:100 forKey:@"scope"]; [archiver encodeObject:@"jack" forKey:@"name"]; //完成編碼,講上面的歸檔數據填充到data中,此時data已經存儲了歸檔對象的數據 [archiver finishEncoding]; NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"array.src"]; BOOL success = [data writeToFile:filePath atomically:YES]; if (success) { NSLog(@"歸檔成功"); } //多個對象解檔 NSData *data2 = [[NSData alloc] initWithContentsOfFile:filePath]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data2]; NSArray *array = [unarchiver decodeObjectForKey:@"array"]; NSLog(@"%@",array); int value = [unarchiver decodeIntForKey:@"scope"]; NSLog(@"%d",value);
[unarchiver finishDecoding];
2.自定義類型的歸檔解檔
上面已經說過了,對系統類型能夠直接進行歸檔和解檔,可是對於自定義類型,必須實現NSCoding協議
#import <Foundation/Foundation.h> #import "Car.h" int main(int argc, const char * argv[]) { /* 有輛汽車 有一個引擎 和 四個輪胎 而後須要對這個汽車進行歸檔 本地保存數據 這時 還必需要對汽車的引擎和輪胎也要歸檔 只要有成員變量是對象地址 都要繼續歸檔 那麼這時歸檔的類 都要遵照協議NSCoding 實現裏面的方法 實際上 歸檔就是一個深拷貝 */ @autoreleasepool { #if 0 Car *BMW = [[Car alloc] init]; BMW.speed = 100; [BMW run]; //程序結束以前把汽車對象的信息進行保存到本地 //歸檔 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"car.src"]; BOOL ret = [NSKeyedArchiver archiveRootObject:BMW toFile:filePath]; if (ret) { NSLog(@"汽車對象歸檔成功"); }else { NSLog(@"汽車歸檔失敗"); } [BMW release]; #else //解歸檔-->從文件中獲取數據建立一個Car對象 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"car.src"]; Car *car = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"car.speed:%ld",car.speed); NSLog(@"engine.name:%@",car.engine.name); [car run]; #endif } return 0; }
汽車類:
#import <Foundation/Foundation.h> #import "Engine.h" #import "Tyre.h" //遵照歸檔協議 @interface Car : NSObject<NSCoding> { Engine *_engine; NSMutableArray *_tyresArr; NSInteger _speed; } @property (nonatomic) NSInteger speed; @property (nonatomic,retain) Engine *engine; - (Car *)init; - (void)run; @end
#import "Car.h" @implementation Car - (void)dealloc { NSLog(@"汽車銷燬"); [_engine release]; [_tyresArr release]; [super dealloc]; } //對Car歸檔的時候會調用的方法 - (void)encodeWithCoder:(NSCoder *)aCoder { //就是對成員變量的數據進行歸檔 //若是成員變量是基本類型 那麼直接歸檔 //若是成員變量變量是對象地址 那麼對象的類也要遵照協議實現方法 //在類中 若是有setter和getter方法那麼儘可能使用setter和getter方法 [aCoder encodeInteger:self.speed forKey:@"speed"]; //對一個對象地址指向的對象進行歸檔 那麼指向對象也要實現歸檔協議的方法 Engine 要遵照 數組要遵照 數組的元素也要遵照 [aCoder encodeObject:self.engine forKey:@"engine"]; [aCoder encodeObject:_tyresArr forKey:@"array"]; } //對象解歸檔、讀檔的時候調用 - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) {//若是父類有initWithCoder那麼調用父類的initWithCoder: //這裏不要直接寫 成員變量 不然就有可能崩潰 //要用setter方法 這樣 內部會計數器+1 擁有絕對使用權 //讀檔 self.engine = [aDecoder decodeObjectForKey:@"engine"]; NSLog(@"%ld",self.engine.retainCount); self.speed = [aDecoder decodeIntegerForKey:@"speed"]; //要注意擁有絕對使用權 _tyresArr = [[aDecoder decodeObjectForKey:@"array"] retain]; } return self; } - (Car *)init { if (self = [super init]) { _engine = [[Engine alloc] init]; _engine.name = @"德國"; _engine.power = 1000; _tyresArr = [[NSMutableArray alloc] init]; for (int i = 0; i < 4; i++) { Tyre *tyre = [[Tyre alloc] init]; tyre.name = @"米其林"; tyre.type = 12345; [_tyresArr addObject:tyre]; [tyre release]; } } return self; } - (void)run { NSLog(@"汽車跑"); [self.engine start]; for (Tyre *tyre in _tyresArr) { [tyre scroll];//滾動 } } @end
輪胎類:
#import <Foundation/Foundation.h> @interface Tyre : NSObject<NSCoding> { NSString *_name; NSInteger _type; } @property (nonatomic,copy)NSString *name; @property (nonatomic)NSInteger type; - (void)scroll; @end
#import "Tyre.h" @implementation Tyre - (void)dealloc { NSLog(@"輪胎銷燬"); self.name = nil; [super dealloc]; } //歸檔調用 - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.name forKey:@"name"]; [aCoder encodeInteger:self.type forKey:@"type"]; } //讀檔調用 - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { //用setter方賦值 內部有計數器+1 self.name = [aDecoder decodeObjectForKey:@"name"]; self.type = [aDecoder decodeIntegerForKey: @"type"]; } return self; } - (void)scroll { NSLog(@"%@ 輪胎在滾動",self.name); } @end
引擎類:
#import <Foundation/Foundation.h> @interface Engine : NSObject <NSCoding> { NSString *_name; NSInteger _power; } @property (nonatomic,copy)NSString *name; @property (nonatomic) NSInteger power; - (void)start; @end
#import "Engine.h" @implementation Engine - (void)dealloc { NSLog(@"引擎銷燬"); self.name = nil; [super dealloc]; } //歸檔調用 - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.name forKey:@"name"]; [aCoder encodeInteger:self.power forKey:@"power"]; } //讀檔調用 - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { self.name = [aDecoder decodeObjectForKey:@"name"]; self.power = [aDecoder decodeIntegerForKey: @"power"]; } return self; } - (void)start { NSLog(@"引擎啓動"); } @end