UI(十六)資料持久化和歸檔NSCoding序列化

weixin_33758863發表於2018-07-30

#pragma mark---目錄---

 1、兩個目錄:

①、沙盒 (有三個資料夾 docments temp library)

②、bundle 在執行的時候 只能讀資料 寫不進去資料

 2、讀取路徑方式

 bundle目錄:[NSBundle mainBundle]

 根目錄:NSHomeDirectory()

 tmp:NSTemporaryDirectory()


 ①、查詢路徑陣列

NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)

 ②、找到指定路徑

 取第一個或最後一個元素

 Documents:NSDocumentDirectory

 library:NSLibraryDirectory

 Caches:NSCachesDirectory


 讀寫檔案

 陣列 字典 字串

 write

 ContentsOfFile


 [陣列物件 writeToFile:path atomically:YES]

 [字典物件 writeToFile:path atomically:YES]

 [字串物件 writeToFile:path atomically:YESencoding:NSUTF8StringEncoding error:nil]


 [NSArray arrayWithContentsOfFile:path]

 [NSDictionary dictionaryWithContentsOfFile:path]

[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]

 #pragma mark---正文---

 資料持久化:把快閃記憶體上的資料以檔案的形式儲存下來(儲存到磁碟)它的目的是為了儲存資料

 1、plist

 2、NSUserDefaults

 3、歸檔 NSCoding 序列化

 4、sqlite(資料庫)

 5、coreData(蘋果專有資料庫)


 路徑:檔案儲存的位置

 ios專有的沙盒機制:bandBox  IOS的應用程式裡,每一個應用程式只能夠讀取寫入本應用程式的沙盒目錄

 沙盒的路徑->應用程式根目錄

 NSLog(@"%@",NSHomeDirectory());列印根目錄


沙盒目錄的組成:

 1、Documents:可以開放讀取寫入的許可權->裡面所有的檔案都可以匯出或者拖進去->不要放一些隱私的檔案

 怎樣開啟? 

    info.plist檔案裡面新增 Application supports iTunes file sharing 把這個key對應的值改成YES就可以分享Documents目錄

 2、Library:存放配置資訊或者資料庫資原始檔

 3、tmp:臨時檔案儲存的地方 隔一段時間會清除一次(可以設定)->不能放重要的檔案(資料庫)

 bundle目錄:應用程式右鍵顯示包內容的目錄 不允許應用程式在執行的時候寫入任何資料


 #pragma mark---查詢各個目錄路徑的方式:---

 根目錄:NSHomeDirectory()

 bundle目錄:[NSBundle mainBundle]

 tmp目錄: NSTemporaryDirectory()

 #pragma mark---查詢特殊的幾個目錄---

 Library目錄、Documents目錄、NSCachesDirectory:

 (1)、找到根目錄--NSHomeDirectory() 拼接到Library目錄

 ①通過拼接字串拼接路徑

NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Library"];

NSLog(@"%@",path);

 ②專門用於拼接路徑的方式

 路徑是以“/”來區分的 如果用拼接字串的方式拼接路徑就必須加“/”

 如果用拼接路徑的方式拼接路徑就不能加“/”

NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library"];

NSLog(@"%@",path);

 (2)、查詢使用者應用程式的範圍 查詢Library目錄

 記:查詢目錄會得到一個陣列 Search(查詢)

 ① 先找到某個路徑的陣列

NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);


     NSSearchPathForDirectoriesInDomains(要查詢的路徑, 要搜尋的區域範圍, 是不是允許獲得擴充套件的目錄);

 ② 獲得陣列裡面的第一個或者最後一個目錄(只有一個元素),就是要查詢的目錄

 NSString *path3 = [pathList lastObject];

NSLog(@"%@",path3);


 #pragma mark---寫入讀取檔案:---

 字典、陣列都有讀取寫入檔案的方法

 1、寫入到plist檔案裡面

 2、

 陣列讀取檔案

 arrayWithContentsOfFile:(NSString *)path

 initWithContentsOfFile:(NSString *)path

 陣列寫入內容

 - (BOOL)writeToFile:檔案路徑 atomically:(BOOL)useAuxiliaryFile

**atomically 如果設定成YES 不會直接寫入到指定檔案 先寫入到一個臨時檔案 暫存一下 當寫入完畢才會存入到指定檔案 如果遇到(斷電 閃退 來電話...)就會刪除臨時檔案 不去寫入到指定檔案 防止寫入資料不完整 在使用的時候出現崩潰

 如果設定成NO 不管任何情況 都會寫入


 字典讀取檔案

 dictionaryWithContentsOfFile:(NSString *)path

 initWithContentsOfFile:(NSString *)path

 字典寫入檔案

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile


 字串讀取檔案

  initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error

 stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error


NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

 字串寫入檔案

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error


 NSError *error;

[content writeToFile:path atomically:YESencoding:NSUTF8StringEncoding error:&error];

--------------------------------------------------------------------

#pragma mark---歸檔---

*歸檔->資料持久化的方式->加密(把檔案加密《不是把資料加密》)

*歸檔分為:

 1、儲存資料(編碼、序列化、歸檔過程)

 2、讀取資料(解碼、反序列化、解歸檔過程)


*可以歸檔的物件:必須遵守歸檔協議(NSSecureCoding遵守NSCoding)、實現協議方法


*除了NSObject未實現歸檔協議 其他實現了協議的類 都可以歸檔(UIViewController、UIView...)


歸檔類名:NSKeyedArchiver

解歸檔類名:NSKeyedUnarchiver


*歸檔、解歸檔 都是通過key來實現的

*在歸檔、解歸檔的時候 key一定要對應(儘量和物件名相同)

#pragma mark-----歸檔的步驟--------

1、寫儲存歸檔檔案的路徑

NSArray *searchList = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);

 *歸檔檔案的尾綴儘量用 .archiver

NSString *path = [[searchList lastObject]stringByAppendingPathComponent:@"list.archiver"];

2、準備要歸檔的資料

NSArray *list = @[@{@"name":@"小明", @"age":@(18), @"height":@(18.5)}];

3、開始歸檔

*把一個Object(支援歸檔)的資料 以歸檔的形式儲存到指定位置

 + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;

*支援歸檔協議的物件 系統幫忙對他進行了編碼

 BOOL isSuccess = [NSKeyedArchiver archiveRootObject:list toFile:path];

 if (isSuccess) {

NSLog(@"%@",path);

    }

#pragma mark-----解歸檔的步驟------

1、歸檔檔案路徑

2、開始解歸檔

 + (nullable id)unarchiveObjectWithFile:(NSString *)path

    NSArray *list = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

#pragma mark---NSData二進位制的類---

*NSData 二進位制的類 可以把檔案或者資料轉成二進位制的物件

#pragma mark---多種資料歸檔步驟---

1、儲存路徑

NSArray *searchList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

 NSString *path = [[searchList lastObject]stringByAppendingPathComponent:@"user.archiver"];

2、初始化一個可變的二進位制物件 **NSMutableData 同時準備要歸檔的資料

NSString *name = @"mary";

 NSInteger age = 18;

 float height = 172.5;


 NSMutableData *Data = [NSMutableData data];

3、歸檔等待寫入資料的二進位制物件(要把二進位制物件寫入到檔案)->讓歸檔物件幫他寫入


     NSKeyedArchiver *arc = [[NSKeyedArchiver alloc]initForWritingWithMutableData:Data];

4、使用歸檔物件 對要歸檔的資料進行編碼(同時寫入到二進位制物件-系統幫我們們操作)(編碼結束就會把編碼後的資料寫入二進位制物件)

*編碼:encode 解碼:decode

*要用對應的資料型別進行編碼

[arc encodeObject:name forKey:@"name"];

[arc encodeInteger:age forKey:@"age"];

[arc encodeFloat:height forKey:@"height"];

5、編碼結束

*把編碼之後資料寫入到二進位制物件

     [arc finishEncoding];

6、把二進位制物件儲存到指定位置

 BOOL isSuccess = [Data writeToFile:path atomically:YES];

 if (isSuccess) {

NSLog(@"%@",path);

#pragma mark---多種解歸檔---

 **decode 解碼

- (instancetype)initForReadingWithData:(NSData *)data

1、歸檔檔案路徑

2、使用data讀取資料 準備解歸檔data裡面的資料

    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:[NSData dataWithContentsOfFile:path]];

3、解歸檔資料 用對應的資料型別接收

 NSString *name = [unarchiver decodeObjectForKey:@"name"];

 NSInteger age = [unarchiver decodeIntegerForKey:@"age"];

 float height = [unarchiver decodeFloatForKey:@"height"];

 NSLog(@"%@  %ld  %f",name,age,height);


#pragma mark---*自定義歸檔*---

自定義歸檔->有些資料不能歸檔->讓他遵守歸檔協議(NSCoding)->

 歸檔、解歸檔都與第一種方式相同

userModel *user = [[userModel alloc]init];

user.name = @"江兒";

user.age = 18;

user.height = 165.5;


 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"user.archiver"];

 BOOL isOK = [NSKeyedArchiver archiveRootObject:user toFile:path];

 if (isOK) {

NSLog(@"%@",path);

    }



 userModel *userMode= [NSKeyedUnarchiverunarchiveObjectWithFile:path];


 NSLog(@"%@ %ld %f",userMode.name,userMode.age,userMode.height);


當在歸檔位置(viewController中)呼叫[NSKeyedArchiver archiveRootObject:XXX toFile:XXX]; 會自動呼叫encodeWithCoder:這個代理方法

使用**歸檔方法對物件歸檔的時候 會呼叫這個方法

- (void)encodeWithCoder:(NSCoder *)aCoder{

    aCoder就是系統傳過來的NSKeyedArchiver例項化出來的物件

[aCoder encodeObject:self.name forKey:@"name"];

[aCoder encodeInteger:self.age forKey:@"age"];

[aCoder encodeFloat:self.height forKey:@"height"];

}


使用**解歸檔方法對物件解歸檔的時候 會呼叫這個方法

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{

 只要是構造方法先把建立物件的方法補全

 //self = [super init];

 //if (self) {

 //}

 //return self;


 self = [super init];

 if (self) {

 當使用解歸檔方法的時候 系統會自動呼叫initWithCoder:這個方法 系統會幫我們們建立一個物件

 之前的物件的資料儲存在 歸檔檔案裡面

 在解歸檔的時候 還原資料 並且把還原的資料賦值給這個物件->現在這個物件的資料跟原來歸檔的資料是一樣的

 self.name = [aDecoder decodeObjectForKey:@"name"];

 self.age = [aDecoder decodeIntegerForKey:@"age"];

 self.height = [aDecoder decodeFloatForKey:@"height"];


    }


 return self;

}

相關文章