對(duì)模型對(duì)象進(jìn)行歸檔(objective-c)
對(duì)模型對(duì)象進(jìn)行歸檔是4種將數(shù)據(jù)持久存儲(chǔ)在iOS文件系統(tǒng)的機(jī)制之一
使用注意:只要在類中實(shí)現(xiàn)的每個(gè)屬性都是標(biāo)量(枚舉類型、字符型和各種整數(shù)表達(dá)形式)或都是遵循NSCoding協(xié)議的某個(gè)類的實(shí)例棠枉,就可以對(duì)整個(gè)對(duì)象進(jìn)行完全的歸檔浓体。大多數(shù)支持存儲(chǔ)數(shù)據(jù)的Foundation和Cocoa Touch類都遵循NSCoding協(xié)議(不過(guò)有一些例外,如UIImage)辈讶。
盡管對(duì)歸檔沒有嚴(yán)格要求命浴,但一般NSCopying協(xié)議應(yīng)該與NSCoding協(xié)議一起實(shí)現(xiàn),這個(gè)協(xié)議允許復(fù)制對(duì)象贱除,這在使用數(shù)據(jù)模型對(duì)象時(shí)具備較大的靈活性生闲。
一些進(jìn)行歸檔和歸檔重組前的方法
獲取Document目錄,為了將之后歸檔完的數(shù)據(jù)存放于此
-(NSString*)dataFilePath
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//傳遞了三個(gè)參數(shù),分別代表的是正在查找的路徑月幌,此次搜索限制在應(yīng)用沙盒內(nèi)碍讯,是否展開完整路徑(YES)
NSString *documentsDirectory=[paths objectAtIndex:0];
//每個(gè)應(yīng)用只有一個(gè)Document路徑,所以返回?cái)?shù)組的第一個(gè)就是所需項(xiàng)
return [documentsDirectory stringByAppendingPathComponent:@"data.archiver"];
//在路徑的結(jié)尾附上文件名就可以創(chuàng)建指向該文件的路徑飞醉,如果不存在該文件冲茸,系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)文件。
}
歸檔和歸檔重組需要遵循的兩個(gè)協(xié)議
NSCoding協(xié)議
NSCoding協(xié)議聲明了兩個(gè)方法缅帘,一個(gè)方法將對(duì)象編碼到歸檔中轴术,另外一個(gè)方法對(duì)歸檔解碼來(lái)創(chuàng)建一個(gè)新對(duì)象。
-
將對(duì)象編碼到歸檔中
- 有一個(gè)注意點(diǎn)钦无,如果需要子類化某個(gè)遵循NSCoding的類逗栽,還需要對(duì)其父類調(diào)用encodeWithCoder方法
-(void)encodeWithCoder:(NSCoder*)encoder { [super encodeWithCoder:encoder];//符合上述注意點(diǎn)時(shí)才調(diào)用失暂! [encoder encodexxx:xxx forkey:xxx]; ... }
-
恢復(fù)之前歸檔的對(duì)象
與歸檔方法類似彼宠,當(dāng)為某個(gè)有父類而且遵循NSCoding的類實(shí)現(xiàn)NSCOding時(shí)鳄虱,initWithCoder:方法稍有不同
挺拗口的,實(shí)際上想表達(dá)的意思是凭峡,你要讓一個(gè)類遵循NSCoding協(xié)議的話拙已,需要去實(shí)現(xiàn)他的兩個(gè)requied方法,然后當(dāng)你要實(shí)現(xiàn)這個(gè)initWithCoder:方法的時(shí)候要注意摧冀,你需要判斷現(xiàn)在這個(gè)類有沒有父類倍踪,這個(gè)父類是不是也遵循NSCoding協(xié)議
-(id)initWithCoder:(NSCoder *)aDecoder { self=[super init];//普通調(diào)用 self=[super initWithCoder:aDecoder;//符合上面描述時(shí)調(diào)用 if (self) { xxx=[aDexcoder decodeObjectForKey:xx]; } return self; }
NSCopying協(xié)議
遵循NSCopying對(duì)于任何數(shù)據(jù)模型對(duì)象來(lái)說(shuō)都是非常好的事情,NSCopying有一個(gè)copyWithZone的方法可以用來(lái)復(fù)制對(duì)象
-
此處copyWithZone方法內(nèi)容如下(需要注意的是索昂,在精通iOS開發(fā)這本書的數(shù)據(jù)持久化歸檔這一塊中建车,雖然有遵循這一個(gè)協(xié)議,但是應(yīng)該是沒有實(shí)現(xiàn)調(diào)用里面的方法的)
-(id)copyWithZone:(NSZone *)zone
{
Myclass *copy=[[[self class]allocWithZone:zone]init];
copy.foo=[self.foo copyWithZone:zone];
...
return copy;
}
```
對(duì)數(shù)據(jù)對(duì)象進(jìn)行歸檔和取消歸檔
創(chuàng)建歸檔
從遵循NSCoding的一個(gè)或多個(gè)對(duì)象創(chuàng)建歸檔椒惨,首先創(chuàng)建一個(gè)NSMutableData實(shí)例缤至,用于包含編碼的數(shù)據(jù),然后創(chuàng)建一個(gè)NSKeyedArchiver實(shí)例康谆,用于將對(duì)象歸檔到此NSMutableData實(shí)例中领斥。
NSData和NSMutableData類所創(chuàng)建出來(lái)的實(shí)例是用于存放二進(jìn)制數(shù)的。而此處的NSKeyedArchiver所創(chuàng)建實(shí)例秉宿,可以理解成為一個(gè)壓縮工具戒突,它將原文件化成二進(jìn)制數(shù),便于儲(chǔ)存在Data實(shí)例中描睦。
NSString *filePath=[self dataFilePath];
NSMutableData *data=[[NSMutableData alloc]init];
//創(chuàng)建NSMutableData實(shí)例
NSKeyedArchiver *archiver=[[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
//創(chuàng)建NSKeyedArchiver實(shí)例
[archiver encodeObject:myObject forKey:@"xx"]
//這一句話可以理解為將這個(gè)myObject對(duì)象進(jìn)行歸檔膊存,使用鍵值編碼,其中這個(gè)xxx的鍵就對(duì)應(yīng)這個(gè)對(duì)象的值忱叭。在調(diào)用這條語(yǔ)句以后隔崎,函數(shù)會(huì)跳轉(zhuǎn)到遵循NSCoding協(xié)議的myObject的所屬的類中的encoderWithCoder:方法
[archiver finishEncoding];
[data writeToFile:filePath atomically:YES];
整個(gè)流程可以理解為,首先創(chuàng)建data對(duì)象韵丑,然后以data作為寫入路徑創(chuàng)建archiver對(duì)象爵卒,archiver發(fā)出消息,以xx為鍵將myObject對(duì)象歸檔撵彻,然后函數(shù)跳轉(zhuǎn)至myObject所屬的類中钓株,執(zhí)行encoderWithCoder:方法,將myObject里面所包含的屬性陌僵,對(duì)象再以xxx鍵進(jìn)行歸檔轴合,然后存放在data對(duì)象中,然后將data數(shù)據(jù)根據(jù)Document路徑寫入碗短。
從歸檔重組對(duì)象
創(chuàng)建歸檔和從歸檔重組基本可以看為一個(gè)互逆的過(guò)程受葛,步驟跟思路也相似
NSString *filePath=[self dataFilePath];
NSData *data=[NSData alloc]initWithContentsOfFile:filePath;
//從歸檔文件創(chuàng)建一個(gè)NSData實(shí)例
NSKeyedUnarchiver *unarchiver=[[NSKeyedUnarchiver alloc]initForReadingWithData:data];
//unarchiver相當(dāng)于一個(gè)只服務(wù)于data的解壓器,用于對(duì)數(shù)據(jù)解碼
self.xxx=[unarchiver decodeObjectForKey:xxx;
//這里的key是相對(duì)于歸檔時(shí)候所用的key而言
[unarchiver finishDecoding];
小結(jié)
- 以上代碼片都是參考精通iOS開發(fā)這本書所寫出來(lái)的,可以在這本書的第13章第4小節(jié)參考全部分代碼
- 在這一部分的知識(shí)學(xué)習(xí)過(guò)程中遇到了兩個(gè)問(wèn)題总滩,第一個(gè)是NSCoding實(shí)現(xiàn)方法中的key跟NSKeyedUnarchiver/NSKeyedarchiver中的key有什么不一樣纲堵,第二個(gè)是NSCoding和NSCopying實(shí)現(xiàn)的方法在何處被調(diào)用
- 針對(duì)第一個(gè)問(wèn)題,最后得出的答案是闰渔,NSKeyedUnarchiver/NSKeyedarchiver的Key針對(duì)的是整個(gè)對(duì)象的歸檔/重組席函,而NSCoding方法中的Key針對(duì)的是這個(gè)對(duì)象里面所包含的屬性以及對(duì)象的歸檔/重組。
- 第二個(gè)問(wèn)題冈涧,NSCopying通過(guò)設(shè)置斷點(diǎn)發(fā)現(xiàn)在該書的整段代碼中應(yīng)該是沒有被調(diào)用向挖,而NSCoding的兩個(gè)方法都是在NSKeyedUnarchiver/NSKeyedarchiver所對(duì)應(yīng)的實(shí)例對(duì)象調(diào)用其方法的時(shí)候,函數(shù)跳轉(zhuǎn)至NSCoding的實(shí)現(xiàn)方法。