標籤:ios 資料存放區 資料持久化 歸檔 喜好設定
在iOS學習過程中,有時候需要保持使用者資料,比如登入資訊、使用者的設定選項等,這時候就需要學習資料持久化操作,本節主要學習iOS資料持久化相關的知識。
資料持久化的方式有四種:
1).寫入plist檔案(屬性列表)
2).喜好設定
3).歸檔(NSKeyedArchiver)
4).NSData
下面分別舉例說明四種方式的適用場合以及用法。
1. 寫入plist檔案(屬性列表)
1.1 plist可以儲存哪些資料
屬性列表是一種XML格式的檔案,拓展名為plist
如果對象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,就可以使用writeToFile:atomically:方法直接將對象寫到屬性列表檔案中。
由於plist檔案的root只有Array和Dictionary兩種類型,所以最好只保持它們對應資料類型的資料。
比如當你儲存字串類型的資料的時候,Type就為空白了。
1.2 如何儲存
#pragma mark - 儲存資料- (IBAction)btnSaveData_Click:(UIButton *)sender{ NSString *str = @"hello"; NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"test_str.plist"]; BOOL result = [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; if (result) { NSLog(@"儲存資料成功"); } else { NSLog(@"儲存資料失敗!"); }}
程式運行結果如下:
自動產生的檔案:
注意:plist不能儲存自訂物件類型!
<span style="color:#000000;">#pragma mark - 儲存資料- (IBAction)btnSaveData_Click:(UIButton *)sender{ // 檔案的沙河路徑 NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"test_obj.plist"]; // 建立Student對象 CYStudent *stu = [[CYStudent alloc]init]; stu.name = @"zhangsan"; stu.age = 18; NSArray *arrTmp = @[stu]; BOOL result = [arrTmp writeToFile:filePath atomically:YES]; if (result) { NSLog(@"儲存資料成功"); } else { NSLog(@"儲存資料失敗!"); }}</span> 程式運行結果如下:
1.3 plist檔案的儲存與讀取過程
2. 喜好設定
2.1 使用情境
很多iOS應用都支援喜好設定,比如儲存使用者名稱、密碼、字型大小等設定,iOS提供了一套標準的解決方案來為應用加入喜好設定功能
每個應用都有個NSUserDefaults執行個體,通過它來存取喜好設定。比如,儲存使用者名稱、字型大小、是否自動登入。
2.2 如何使用
登入成功後儲存資料:
[[NSUserDefaults standardUserDefaults]setObject:self.txtAccount.text forKey:@"account"]; [[NSUserDefaults standardUserDefaults]setObject:self.txtPWD.text forKey:@"pwd"]; [[NSUserDefaults standardUserDefaults]setBool:self.swchRememberPWD.on forKey:@"isRememberPWD"]; [[NSUserDefaults standardUserDefaults]setBool:self.swchAutoLogin.on forKey:@"isAutoLogin"];
再次登入時讀取資料:
// 擷取喜好設定中的資料
self.txtAccount.text = [[NSUserDefaults standardUserDefaults]objectForKey:@"account"]; self.swchAutoLogin.on = [[NSUserDefaults standardUserDefaults]boolForKey:@"isAutoLogin"]; self.swchRememberPWD.on = [[NSUserDefaults standardUserDefaults]boolForKey:@"isRememberPWD"]; self.txtPWD.text = [[NSUserDefaults standardUserDefaults]objectForKey:@"pwd"];
注意:UserDefaults設定資料時,不是立即寫入,而是根據時間戳記定時地把緩衝中的資料寫入本地磁碟。所以調用了set方法之後資料有可能還沒有寫入磁碟應用程式就終止了。出現以上問題,可以通過調用synchornize方法強制寫入
[defaults synchornize];
3. 歸檔(NSKeyedArchiver)
3.1 使用場合
如果對象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,可以直接用NSKeyedArchiver進行歸檔和恢複
不是所有的對象都可以直接用這種方法進行歸檔,只有遵守了NSCoding協議的對象才可以
NSCoding協議有2個方法:
1)encodeWithCoder:
每次歸檔對象時,都會調用這個方法。一般在這個方法裡面指定如何歸檔對象中的每個執行個體變數,可以使用encodeObject:forKey:方法歸檔執行個體變數
2)initWithCoder:
每次從檔案中恢複(解碼)對象時,都會調用這個方法。一般在這個方法裡面指定如何解碼檔案中的資料為對象的執行個體變數,可以使用decodeObject:forKey方法解碼執行個體變數
3.2 如何使用
1> 自訂實體類
@interface CYContact : NSObject /** 姓名 */ @property (nonatomic,copy) NSString *name; /** 電話 */ @property (nonatomic,copy) NSString *phone; @end
2> 實現NSCoding協議方法
#pragma mark - NSCoding協議方法 /* Encodes the receiverusing a given archiver 通過一個給定的archiver把訊息接收者進行編碼。 當接收到encodeObject訊息的時候,類終端encodeWithCoder方法被調用。 */ - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_name forKey:CYNameKey]; [aCoder encodeObject:_phone forKey:CYPhoneKey]; } /* Returns an objectinitialized from data in a given unarchiver. (required) 從一個給定unarchiver的資料中返回一個初始化對象。 */ - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { _name = [aDecoder decodeObjectForKey:CYNameKey]; _phone = [aDecoder decodeObjectForKey:CYPhoneKey]; } return self; } /* Returnsa new instance that’s a copy of the receiver 返回訊息接收者的一個複製的新執行個體。 */ - (id)copyWithZone:(NSZone *)zone { CYContact *copy = [[[self class] allocWithZone:zone] init]; copy.name = [self.name copyWithZone:zone]; copy.phone = self.phone; return copy; }
3> 歸檔
[NSKeyedArchiver archiveRootObject:self.contacts toFile:CYFilePath];
4> 接檔
self.contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:CYFilePath];
5> 注意點
如果父類也遵守了NSCoding協議,請注意:
? 應該在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];確保繼承的執行個體變數也能被編碼,即也能被歸檔
? 應該在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];確保繼承的執行個體變數也能被解碼,即也能被恢複
4. NSData
4.1 使用場合
使用archiveRootObject:toFile:方法可以將一個對象直接寫入到一個檔案中,但有時候可能想將多個對象寫入到同一個檔案中,那麼 就要使用NSData來進行歸檔對象
NSData可以為一些資料提供臨時儲存空間,以便隨後寫入檔案,或者存放從磁碟讀取的檔案內容。可以使用[NSMutableData data]建立 可變資料空間
註:黑色箭頭表示將對象歸檔到檔案中,紅色箭頭表示從檔案中恢複對象
4.2 如何使用
#pragma mark - 儲存資料- (IBAction)btnSaveData_Click:(UIButton *)sender{ // NSData-歸檔2個Person對象到同一檔案中 // 執行個體化對象 CYStudent *stu1 = [CYStudent studentWithName:@"zhangsan" age:18]; CYStudent *stu2 = [CYStudent studentWithName:@"lisi" age:20]; // 建立一塊可變資料區 NSMutableData *data = [NSMutableData data]; // 將資料區串連到一個NSKeyedArchiver對象 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; // 開始存檔對象,存檔的資料都會儲存到NSMutableData中 [archiver encodeObject:stu1 forKey:@"stu1"]; [archiver encodeObject:stu2 forKey:@"stu2"]; // 存檔完畢(一定要調用這個方法) [archiver finishEncoding]; NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"datas.data"]; // 將存檔的資料寫入檔案 BOOL result = [data writeToFile:path atomically:YES]; if (result) { NSLog(@"儲存資料成功"); } else { NSLog(@"儲存資料失敗!"); }}#pragma mark - 讀取資料- (IBAction)btnReadData_Click:(UIButton *)sender{ // NSData-從同一檔案中恢複2個Person對象 // 從檔案中讀取資料 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"datas.data"]; NSData *data = [NSData dataWithContentsOfFile:path]; // 根據資料,解析成一個NSKeyedUnarchiver對象 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; CYStudent *stu1 = [unarchiver decodeObjectForKey:@"stu1"]; CYStudent *stu2 = [unarchiver decodeObjectForKey:@"stu2"]; // 恢複完畢 [unarchiver finishDecoding]; NSLog(@"%@",stu1); NSLog(@"%@",stu2);}#pragma mark - 利用歸檔實現深複製- (IBAction)btnDeepCopy_Click:(UIButton *)sender{ // 比如對一個CYStudent對象進行深複製 // 臨時儲存stu1的資料 CYStudent *stu1 = [CYStudent studentWithName:@"zhangsan" age:18]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:stu1]; // 解析data,產生一個新的Person對象 CYStudent *stu2 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // 分別列印記憶體位址 NSLog(@"stu1:%p", stu1); // stu1:0x7bdb32b0 NSLog(@"stu2:%p", stu2); // stu2:0x7bdb6b80}
iOS學習筆記-資料持久化