iOS - 資料持久化 - 檔案的寫入(簡單物件和複雜物件)
資料持久化的本質 -資料儲存成檔案,儲存到程式的沙盒中
-在應用程式結束時,將記憶體中的資料以檔案的形式搬到(儲存到)硬碟中
沙盒機制(Sand box):是個安全機制-這就是ios和Mac系統安全的原因,就是因為它採用了沙盒機制
越獄之後沙盒機制被損壞了,應用程式之間可能會相互盜取資訊
沙盒其實是個資料夾,名字是隨機分配的,我們叫它UID(全球唯一識別符號,只有這個應用程式自身知道這個ID,其他應用程式是不知道的)
一、獲取沙盒下檔案的路徑
//1.獲取當前應用程式的沙盒主路徑(沙盒化的應用程式所能訪問的資料夾路徑只有自己所產生的沙盒資料夾下的相關子資料夾,包括:Documents, Library, tmp
NSString *sandboxPath = NSHomeDirectory();
NSLog(@"%@",sandboxPath);
結果:/Users/xalo/Library/Developer/CoreSimulator/Devices/3A5016C9-61FD-4384-B8C8-D00FD78FAC4F/data/Containers/Data/Application/3936C752-77D1-439C-83D9-348189C81A0B
3A5016C9-61FD-4384-B8C8-D00FD78FAC4F當前模擬器的串號
3936C752-77D1-439C-83D9-348189C81A0B
//2.獲取臨時資料夾路徑tmp,tmp資料夾路徑適合儲存一些臨時檔案,不適合用於儲存重要使用者資料,因為當手機容量已滿時系統會把所有應用它程式的tmp資料夾清空一遍
NSString*tmpPath= NSTemporaryDirectory(); //方法一
NSLog(@"%@",tmpPath);
NSString*tmpPath1= [sandboxPath stringByAppendingPathComponent:@"tmp"]; //方法二:stringByAppendingPathComponent:拼接字串路徑元件(元件就是資料夾或者檔名)- 會自帶“/”
//3.通過路徑搜尋函式獲取對應的Documents資料夾路徑
//第一個引數:被搜尋的資料夾目錄列舉值
//第二個引數:搜尋域-在iOS中只有NSUserDomainMask可用
//第三個引數:是否顯示完整路徑, YES表示返回完整路徑
NSArray *paths= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //補充:生成的路徑是唯一的,陣列中只有一個元素 1.第一個引數:目錄(路徑)名稱2.第二個引數:指定搜尋域(此處是user作用域) 嚴謹起見,不要把域名指定成:NSAllDomainsMask,而是指定成NSUserDomainMask 3.是否使用完整的路徑名稱(1)NO-~/Documents" (2)YES
NSString *documentsPath= paths.firstObject; //或者paths.lastObject
NSLog(@"doc---%@",documentsPath);
二、簡單物件寫入檔案
//簡單物件寫入檔案包含:NSString,NSArray,NSDictionary, NSData等類及其子類的物件寫入到指定路徑的檔案
//1.指定物件將要儲存的沙盒檔案路徑
//2.構造對應累的物件
//3.呼叫該類自己的writeToFile開頭的寫入檔案的方法,將物件的內容寫入到檔案中儲存在對應的沙盒路徑下
舉例:
//1.字串物件寫入檔案
//(1).生成文字檔案的儲存路徑
NSString *textPath = [documentsPath stringByAppendingPathComponent:@"text.txt"];
//(2).建立需要被儲存的字串物件
NSString *string= @"這是一條測試文字";
//(3).將字串寫入對應路徑的檔案
[string writeToFile:textPathatomically:YESencoding:NSUTF8StringEncodingerror:nil];//automically保證多執行緒的安全,加鎖解鎖,保證我寫完之後,才可以做別的操作, error:一般寫入不會有錯,置為nil
//2.陣列物件寫入檔案中
//1.指定陣列的檔案儲存路徑
NSString *arrayPath= [documentsPath stringByAppendingPathComponent:@"array.plist"]; //plist=property list plist是蘋果專用的配置檔案,儲存配置選項,本質是XML(Extensible markable language -可擴充套件標記語言)
//2.建立要寫入檔案的物件
NSArray *array = @[@"I", @"am", @"the", @"best", @"one", @"."];
//2.呼叫陣列的writeToFile:atomically:方法將陣列內容寫入到檔案中
[array writeToFile:arrayPath atomically:YES];
/*
用文字編輯器顯示的結果
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<array>
<string>I</string>
<string>am</string>
<string>the</string>
<string>best</string>
<string>one</string>
<string>.</string>
</array>
</plist>
*/
//3.將字典資料寫入檔案
//1.定義一個字典的檔案儲存路徑
NSString *dicPath = [documentsPath stringByAppendingPathComponent:@"dic.plist"];
//2.建立字典物件
NSDictionary *dic = @{@"name" : @"laomou", @"age" : @28, @"height" : @"178"};
//3.呼叫字典中定義的例項方法writeToFile:atomically:將字典的內容寫入到對應路徑檔案中
[dic writeToFile:dicPath atomically:YES];
//4. NSData二進位制位元組流-二進位制物件寫入檔案
//1.
UIImage *image = [UIImageimageNamed:@"Highest.jpg"];
//2.image無法直接寫入檔案,可以先轉換成二進位制
NSData *imageData= UIImageJPEGRepresentation(image, 0.5);//第二個引數:CGFloatcompressionQuality -壓縮質量,範圍在0~1之間, 1代表是100%不壓縮
//3.建立-該方法可以用來壓縮上傳的頭像
NSString *imagePath = [documentsPath stringByAppendingPathComponent:@"image.jpg"];
//4.將二進位制位元組流物件寫入到檔案中
[imageData writeToFile:imagePath atomically:YES];
寫入的檔案如下圖:
三、複雜物件寫入檔案(複雜物件(框架中不存在的類-自定義的物件))
//對於自定義類的例項物件,需要通過歸檔和反歸檔來進行持久化儲存-這並不是最優化的方式,優選的是使用資料庫
//1.對應類遵守NSCoding協議
//2.實現相關的編碼(-(void)encodeWithCoder:(NSCoder*)aCoder)和解碼(-(id)initWithCoder:(NSCoder *)aDecoder)協議
//3.使用NSKeyedArchiver來進行歸檔儲存(呼叫編碼協議)
//4.使用NSKeyedUnarchiver來進行反歸檔(呼叫解碼協議)
舉例:
Student *stu1 = [StudentstudentWithName:@"zhangsan"age:25 sex:@"male"];
Student *stu2= [StudentstudentWithName:@"lisi"age:24sex:@"女"];
Student *stu3= [StudentstudentWithName:@"wangwu"age:24sex:@"男"];
//NSCoding - 編碼和解碼協議必須實現NSCoding協議,並且要實現協議方法
//編碼(encode)的時候key可以隨便寫,但是解碼(decode)的時候必須和編碼的時候的key對應-規範的寫法就是提前把key定義成巨集,用的時候用巨集就可以了
1.在Student.h中讓要歸檔的Student遵循NSCoding協議
@interfaceStudent: NSObject <NSCoding>//如果一個自定義類的例項物件需要被持久化儲存在沙盒檔案中,則該類需要遵循編碼協議,並實現編碼協議中的編碼和解碼方法
2.在Student.m中實現協議方法(該協議中共有以下兩個協議方法)
//實現編碼協議,讓當前類在歸檔的時候對對應的屬性值做編碼
- (void)encodeWithCoder:(NSCoder*)aCoder {
NSLog(@"%s",__func__);
[aCoder encodeObject:self.name forKey:kStudentNameKey];
[aCoder encodeObject:self.sex forKey:kStudentSexKey];
[aCoder encodeInteger:self.age forKey:kStudentAgeKey];
}
//實現解碼協議,當此類的物件被反歸檔時,首先通過解碼協議方法來獲取對應的屬性值
- (id)initWithCoder:(NSCoder*)aDecoder {
self = [super init];
if (self) {
self.name= [aDecoder decodeObjectForKey:kStudentNameKey];
self.age= [aDecoder decodeIntegerForKey:kStudentAgeKey];
self.sex= [aDecoder decodeObjectForKey:kStudentSexKey];
NSLog(@"%s",__func__);
}
return self;
}
3.使用NSKeyedArchiver來進行歸檔儲存
//如果要將自定義類的物件寫入檔案中,則需要使用歸檔
[NSKeyedArchiver archiveRootObject:studentstoFile:stusPath];
4.使用NSKeyedUnarchiver來進行反歸檔
//如果想要讀取已經歸檔的檔案,則需要反歸檔
NSArray *unArcStus = [NSKeyedUnarchiverunarchiveObjectWithFile:stusPath];
for (Student*stu in unArcStus) {
NSLog(@"%@%lu, %@",stu.name,stu.age,stu.sex);
}