iOS資料持久化之二——歸檔與設計可存儲化的資料模型基類
一、引言
在上一篇部落格中,我們介紹了用plist檔案進行資料持久化的方法。雖然簡單易用,但随着開發的深入,你會發現,這種方式還是有很大的局限性。試想,如果我們可以将使用者的登入傳回資訊模型,遊戲中角色的屬性資訊模型進行直接的持久化存取,那是不是非常爽的事,幸運的是,我們可以通過歸檔,來設計一個這樣的資料模型。
二、先來精通歸檔吧
歸檔也是iOS提供給開發者的一種資料存儲的方式,事實上,幾乎所有的資料類型都可以通過歸檔來進行存取。其存儲與讀取的過程,主要封裝在兩個類中:NSKeyedArchiver和NSKeyedUnarchiver。
1、歸檔的原理
歸檔是将一種或者多種資料類型進行序列化,解歸檔的過程就是将序列化的資料進行反序列化的解碼,這裡需要注意一點,歸檔的核心并非是資料的持久化處理,而是資料的序列化處理,持久化的處理依然是通過檔案存取來實作的。是以,被歸檔的資料類型都必須遵守一個相同的協定,才能在這個協定的限制下進行正确的歸檔與解歸檔,這個協定就是NSCoding協定,我們可以先來看一下NSCoding中的内容:
@protocol NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder;
@end
這個協定非常簡單,一個init的歸檔方法,一個encode的解歸檔方法,NSCoder就是歸檔對象。原則上說,無論是什麼資料類型的對象,系統的或者是我們自定義的,都可以通過實作這個協定中的方法來支援歸檔操作。
2、幾種歸檔與解歸檔的應用
(1)通過類方法來對rootKey進行歸檔
這種方式,我個人了解,很類似于NSUserDefaults中的standardUserDefaults,隻是後者是系統為我們建立的一個預設plist檔案,而rootKey是系統為我們建立的一個預設的歸檔鍵值。說起來比較複雜,舉個例子就十厘清晰了:
NSString *homeDictionary = NSHomeDirectory();//擷取根目錄
NSString *homePath = [homeDictionary stringByAppendingPathComponent:@"atany.archiver"];//添加儲存的檔案名
//方式一:通過data資料歸檔,在将資料寫入檔案
NSData *data= [NSKeyedArchiver archivedDataWithRootObject:@"123"];
[data writeToFile:homePath atomically:YES];
//方式二:直接寫入檔案
[NSKeyedArchiver archiveRootObject:@"456" toFile:homePath];
//方式一和方式二的效果完全一樣 隻是解歸檔的時候不同
//方式一的解歸檔:先擷取data資料,在進行data資料的解歸檔
NSLog(@"%@",[NSKeyedUnarchiver unarchiveObjectWithData:data]);
//方式二的解歸檔:直接解檔案中的歸檔
NSLog(@"%@",[NSKeyedUnarchiver unarchiveObjectWithFile:homePath]);
上面的示例是對字元串類型進行的歸檔,是對單一的資料對象進行的歸檔,當然,這裡的對象是支援數組、字典等集合的,但集合其中的對象,也必須全部支援歸檔操作。
(2)通過構造新的archiver對象,對多個對象進行歸檔
除了上面的類方法,我們還可以自己構造一個歸檔對象,來對多種不同的對象進行歸檔:
//這裡建立一個可變的data對象作為歸檔的容器
NSMutableData * data = [[NSMutableData alloc]init];
//建立一個歸檔對象,歸檔後寫入data資料
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
//對下面的字元串和int值進行歸檔序列化
[archiver encodeObject:@"jaki" forKey:@"name"];
[archiver encodeInt:24 forKey:@"age"];
//寫入data
[archiver finishEncoding];
//寫入檔案
//建立解歸檔的反序列化對象
NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
//進行反序列化
NSString * name = [unarchiver decodeObjectForKey:@"name"];
int age = [unarchiver decodeIntForKey:@"age"];
//列印資訊
NSLog(@"\nname:%@\nage:%d",name,age);
結果如下: