資料儲存(歸檔解檔,沙河儲存)

weixin_33728268發表於2018-03-27

資料儲存

iOS應用資料儲存的常用方式

  • XML屬性列表(plist)歸檔 存Documents中
  • Preference(偏好設定) 存Library/Preference中
  • NSKeyedArchiver歸檔(NSCoding),自定義物件安全
  • SQLite3
  • Core Data

一、應用沙盒

  • 每個iOS應用都有自己的應用沙盒(應用沙盒就是檔案系統目錄),與其他檔案系統隔離。應用必須待在自己的沙盒裡,其他應用不能訪問該沙盒
  • 模擬器應用沙盒的根路徑在: (apple是使用者名稱, 7.0是模擬器版本)
    /Users/apple/Library/Application Support/iPhone Simulator/7.0/Applications

1、應用沙盒結構分析

  • 應用程式包:(上圖中的Layer)包含了所有的資原始檔和可執行檔案

Documents:

  • 儲存應用執行時生成的需要持久化的資料,iTunes同步裝置時會備份該目錄。重要資料例如,遊戲應用可將遊戲存檔儲存在該目錄

tmp:

  • 儲存應用執行時所需的臨時資料,使用完畢後再將相應的檔案從該目錄刪除。應用沒有執行時,系統也可能會清除該目錄下的檔案。iTunes同步裝置時不會備份該目錄

Library/Caches:

  • 儲存應用執行時生成的需要持久化的資料,iTunes同步裝置時不會備份該目錄。一般儲存體積大、不需要備份的非重要資料

Library/Preference:

  • 儲存應用的所有偏好設定,iOS的Settings(設定)應用會在該目錄中查詢應用的設定資訊。iTunes同步裝置時會備份該目錄

2、應用沙盒目錄的常見獲取方式

沙盒根目錄:

NSString *home = NSHomeDirectory();

Documents:(2種方式)

  • 利用沙盒根目錄拼接”Documents”字串
  • 利用NSSearchPathForDirectoriesInDomains函式
//第一種
// 不建議採用,因為新版本的作業系統可能會修改目錄名
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];

//第二種
//利用NSSearchPathForDirectoriesInDomains函式
//NSDocumentDirectory代表查詢Documents資料夾
// NSUserDomainMask 代表從使用者資料夾下找
// YES 代表展開路徑中的波浪字元“~”
NSArray *array =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中,只有一個目錄跟傳入的引數匹配,所以這個集合裡面只有一個元素
NSString *documents = [array objectAtIndex:0];

tmp:

  • 獲取 tmp 目錄
NSString *tmp = NSTemporaryDirectory();

Library/Caches:(跟Documents類似的2種方法)

  • 利用沙盒根目錄拼接”Caches”字串
  • 利用NSSearchPathForDirectoriesInDomains函式(將函式的第2個引數改為:NSCachesDirectory即可)
//利用NSSearchPathForDirectoriesInDomains函式
//NSDocumentDirectory代表查詢Documents資料夾
// NSUserDomainMask 代表從使用者資料夾下找
// YES 代表展開路徑中的波浪字元“~”
NSArray *array =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSCachesDirectory, NO);
// 在iOS中,只有一個目錄跟傳入的引數匹配,所以這個集合裡面只有一個元素
NSString *documents = [array objectAtIndex:0];

Library/Preference:

  • 通過NSUserDefaults類存取該目錄下的設定資訊
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

二、屬性列表

屬性列表是一種XML格式的檔案,擴充名為plist

  • 如果物件是NSString、NSDictionary、NSArray、NSData、NSNumber等型別,就可以使用writeToFile:atomically:方法直接將物件寫到屬性列表檔案中

將一個NSDictionary物件歸檔到一個plist屬性列表中

  • writeToFile方法
// 將資料封裝成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母雞" forKey:@"name"];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 將字典持久化到Documents/stu.plist檔案中
[dict writeToFile:path atomically:YES];

讀取屬性列表,恢復NSDictionary物件

  • dictionaryWithContentsOfFile 方法
// 讀取Documents/stu.plist的內容,例項化NSDictionary
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"name:%@", [dict objectForKey:@"name"]);
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
NSLog(@"age:%@", [dict objectForKey:@"age"]);
列印資訊如下

三、偏好設定

  • 偏好設定是專門用來儲存應用程式的配置資訊的, 一般情況不要再偏好設定中儲存其他資料
  • 如果利用系統的偏好設定來儲存資料, 預設就是儲存在Preferences資料夾下面的
  • 偏好設定會將所有的資料儲存到同一個檔案中

很多iOS應用都支援偏好設定,比如儲存使用者名稱、密碼、字型大小等設定,iOS提供了一套標準的解決方案來為應用加入偏好設定功能

  • 每個應用都有個NSUserDefaults例項,通過它來存取偏好設定
    比如,儲存使用者名稱、字型大小、是否自動登入
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];

讀取上次儲存的設定

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];
  • 注意:UserDefaults設定資料時,不是立即寫入,而是根據時間戳定時地把快取中的資料寫入本地磁碟。所以呼叫了set方法之後資料有可能還沒有寫入磁碟應用程式就終止了。
  • 出現以上問題,可以通過呼叫synchornize方法強制寫入
[defaults synchornize];

四、NSKeyedArchiver

如果物件是NSString、NSDictionary、NSArray、NSData、NSNumber等型別,可以直接用NSKeyedArchiver進行歸檔和恢復

  • 不是所有的物件都可以直接用這種方法進行歸檔,只有遵守了NSCoding協議的物件才可以

NSCoding協議有2個方法:

encodeWithCoder:

  • 每次歸檔物件時,都會呼叫這個方法。一般在這個方法裡面指定如何歸檔物件中的每個例項變數,可以使用encodeObject:forKey:方法歸檔例項變數

initWithCoder:

  • 每次從檔案中恢復(解碼)物件時,都會呼叫這個方法。一般在這個方法裡面指定如何解碼檔案中的資料為物件的例項變數,可以使用decodeObject:forKey方法解碼例項變數

NSKeyedArchiver-歸檔Person物件(Person.m)

@interface Person : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;
@end
//-----------------
@implementation Person
- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeInt:self.age forKey:@"age"];
    [encoder encodeFloat:self.height forKey:@"height"];
}
- (id)initWithCoder:(NSCoder *)decoder {
    self.name = [decoder decodeObjectForKey:@"name"];
    self.age = [decoder decodeIntForKey:@"age"];
    self.height = [decoder decodeFloatForKey:@"height"];
    return self;
}
- (void)dealloc {
    [super dealloc];
    [_name release];
}
@end

歸檔(編碼)

  • archiveRootObject
Person *person = [[[Person alloc] init] autorelease];
person.name = @"MJ";
person.age = 27;
person.height = 1.83f;
[NSKeyedArchiver archiveRootObject:person toFile:path];

恢復(解碼)

  • unarchiveObjectWithFile
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

NSKeyedArchiver-歸檔物件的注意

  • 如果父類也遵守了NSCoding協議,請注意:
    • 應該在encodeWithCoder:方法中加上一句
    • [super encodeWithCode:encode];
    • 確保繼承的例項變數也能被編碼,即也能被歸檔
  • 應該在initWithCoder:方法中加上一句
    • self = [super initWithCoder:decoder];
    • 確保繼承的例項變數也能被解碼,即也能被恢復

相關文章