iOS應(yīng)用數(shù)據(jù)存儲的常用方式
- XML屬性列表(plist)歸檔
- Preference(偏好設(shè)置)
- NSKeyedArchiver歸檔(NSCoding)
- SQLite3
- Core Data
應(yīng)用沙盒
- 每個iOS應(yīng)用都有自己的應(yīng)用沙盒(應(yīng)用沙盒就是文件系統(tǒng)目錄),與其他文件系統(tǒng)隔離。應(yīng)用必須待在自己的沙盒里赃额,其他應(yīng)用不能訪問該沙盒
- 應(yīng)用沙盒的文件系統(tǒng)目錄,如下圖所示(假設(shè)應(yīng)用的名稱叫Layer)
- 模擬器應(yīng)用沙盒的根路徑在: (apple是用戶名, 8.0是模擬器版本)
/Users/apple/Library/Application Support/iPhone Simulator/8.0/Applications
應(yīng)用沙盒結(jié)構(gòu)分析
應(yīng)用程序包:(上圖中的Layer)包含了所有的資源文件和可執(zhí)行文件
Documents:保存應(yīng)用運(yùn)行時生成的需要持久化的數(shù)據(jù)熟尉,iTunes同步設(shè)備時會備份該目錄。例如洲脂,游戲應(yīng)用可將游戲存檔保存在該目錄tmp:保存應(yīng)用運(yùn)行時所需的臨時數(shù)據(jù)斤儿,使用完畢后再將相應(yīng)的文件從該目錄刪除。應(yīng)用沒有運(yùn)行時恐锦,系統(tǒng)也可能會清除該目錄下的文件往果。iTunes同步設(shè)備時不會備份該目錄
Library/Caches:保存應(yīng)用運(yùn)行時生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時不會備份該目錄一铅。一般存儲體積大陕贮、不需要備份的非重要數(shù)據(jù)
Library/Preference:保存應(yīng)用的所有偏好設(shè)置,iOS的Settings(設(shè)置)應(yīng)用會在該目錄中查找應(yīng)用的設(shè)置信息潘飘。iTunes同步設(shè)備時會備份該目錄
應(yīng)用沙盒目錄的常見獲取方式
沙盒根目錄:NSString *home = NSHomeDirectory();
-
Documents:(2種方式)
- 利用沙盒根目錄拼接”Documents”字符串
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
// 不建議采用肮之,因為新版本的操作系統(tǒng)可能會修改目錄名
- 利用NSSearchPathForDirectoriesInDomains函數(shù)
// NSUserDomainMask 代表從用戶文件夾下找
// YES 代表展開路徑中的波浪字符“~”
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中掉缺,只有一個目錄跟傳入的參數(shù)匹配,所以這個集合里面只有一個元素
NSString *documents = [array objectAtIndex:0];
tmp:NSString *tmp = NSTemporaryDirectory();
-
Library/Caches:(跟Documents類似的2種方法)
- 利用沙盒根目錄拼接”Caches”字符串
- 利用NSSearchPathForDirectoriesInDomains函數(shù)(將函數(shù)的第2個參數(shù)改為:NSCachesDirectory即可)
Library/Preference:通過NSUserDefaults類存取該目錄下的設(shè)置信息
屬性列表
- 屬性列表是一種XML格式的文件戈擒,拓展名為plist
- 如果對象是NSString眶明、NSDictionary、NSArray筐高、NSData搜囱、NSNumber等類型,就可以使用writeToFile:atomically:方法直接將對象寫到屬性列表文件中
屬性列表-歸檔NSDictionary
- 將一個NSDictionary對象歸檔到一個plist屬性列表中
// 將數(shù)據(jù)封裝成字典
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];
- 成功寫入到Documents目錄下
- 用文本編輯器凯傲、Xcode打開查看
屬性列表-恢復(fù)NSDictionary
- 讀取屬性列表犬辰,恢復(fù)NSDictionary對象
// 讀取Documents/stu.plist的內(nèi)容,實(shí)例化NSDictionary
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"name:%@", [dict objectForKey:@"name"]);
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
NSLog(@"age:%@", [dict objectForKey:@"age"]);
偏好設(shè)置
- 很多iOS應(yīng)用都支持偏好設(shè)置冰单,比如保存用戶名、密碼灸促、字體大小等設(shè)置诫欠,iOS提供了一套標(biāo)準(zhǔn)的解決方案來為應(yīng)用加入偏好設(shè)置功能
- 每個應(yīng)用都有個NSUserDefaults實(shí)例,通過它來存取偏好設(shè)置
- 比如浴栽,保存用戶名荒叼、字體大小、是否自動登錄
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
- 讀取上次保存的設(shè)置
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];
- 注意:UserDefaults設(shè)置數(shù)據(jù)時典鸡,不是立即寫入被廓,而是根據(jù)時間戳定時地把緩存中的數(shù)據(jù)寫入本地磁盤。所以調(diào)用了set方法之后數(shù)據(jù)有可能還沒有寫入磁盤應(yīng)用程序就終止了萝玷。出現(xiàn)以上問題嫁乘,可以通過調(diào)用synchornize方法強(qiáng)制寫入
[defaults synchornize];
NSKeyedArchiver
- 如果對象是NSString、NSDictionary球碉、NSArray蜓斧、NSData、NSNumber等類型睁冬,可以直接用NSKeyedArchiver進(jìn)行歸檔和恢復(fù)
- 不是所有的對象都可以直接用這種方法進(jìn)行歸檔挎春,只有遵守了NSCoding協(xié)議的對象才可以
- NSCoding協(xié)議有2個方法:
- encodeWithCoder:
每次歸檔對象時,都會調(diào)用這個方法豆拨。一般在這個方法里面指定如何歸檔對象中的每個實(shí)例變量直奋,可以使用encodeObject:forKey:方法歸檔實(shí)例變量 - initWithCoder:
每次從文件中恢復(fù)(解碼)對象時,都會調(diào)用這個方法施禾。一般在這個方法里面指定如何解碼文件中的數(shù)據(jù)為對象的實(shí)例變量脚线,可以使用decodeObject:forKey方法解碼實(shí)例變量
- encodeWithCoder:
NSKeyedArchiver-歸檔NSArray
- 歸檔一個NSArray對象到Documents/array.archive
NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];
- 恢復(fù)(解碼)NSArray對象
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSKeyedArchiver-歸檔Person對象(Person.h)
@interface Person : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;
@end
NSKeyedArchiver-歸檔Person對象(Person.m)
@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
NSKeyedArchiver-歸檔Person對象(編碼和解碼)
- 歸檔(編碼)
Person *person = [[[Person alloc] init] autorelease];
person.name = @"MJ";
person.age = 27;
person.height = 1.83f;
[NSKeyedArchiver archiveRootObject:person toFile:path];
- 恢復(fù)(解碼)
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSKeyedArchiver-歸檔對象的注意
- 如果父類也遵守了NSCoding協(xié)議,請注意:
- 應(yīng)該在encodeWithCoder:方法中加上一句
[super encodeWithCode:encode];
確保繼承的實(shí)例變量也能被編碼拾积,即也能被歸檔 - 應(yīng)該在initWithCoder:方法中加上一句
self = [super initWithCoder:decoder];
確保繼承的實(shí)例變量也能被解碼殉挽,即也能被恢復(fù)
- 應(yīng)該在encodeWithCoder:方法中加上一句
NSData
- 使用archiveRootObject:toFile:方法可以將一個對象直接寫入到一個文件中丰涉,但有時候可能想將多個對象寫入到同一個文件中,那么就要使用NSData來進(jìn)行歸檔對象
- NSData可以為一些數(shù)據(jù)提供臨時存儲空間斯碌,以便隨后寫入文件一死,或者存放從磁盤讀取的文件內(nèi)容∩低伲可以使用[NSMutableData data]創(chuàng)建可變數(shù)據(jù)空間
NSData-歸檔2個Person對象到同一文件中
- 歸檔(編碼)
// 新建一塊可變數(shù)據(jù)區(qū)
NSMutableData *data = [NSMutableData data];
// 將數(shù)據(jù)區(qū)連接到一個NSKeyedArchiver對象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 開始存檔對象投慈,存檔的數(shù)據(jù)都會存儲到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存檔完畢(一定要調(diào)用這個方法)
[archiver finishEncoding];
// 將存檔的數(shù)據(jù)寫入文件
[data writeToFile:path atomically:YES];
NSData-從同一文件中恢復(fù)2個Person對象
- 恢復(fù)(解碼)
// 從文件中讀取數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfFile:path];
// 根據(jù)數(shù)據(jù),解析成一個NSKeyedUnarchiver對象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
// 恢復(fù)完畢
[unarchiver finishDecoding];
利用歸檔實(shí)現(xiàn)深復(fù)制
- 比如對一個Person對象進(jìn)行深復(fù)制
// 臨時存儲person1的數(shù)據(jù)
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];
// 解析data冠骄,生成一個新的Person對象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
// 分別打印內(nèi)存地址
NSLog(@"person1:0x%x", person1); // person1:0x7177a60
NSLog(@"person2:0x%x", person2); // person2:0x7177cf0