UI進(jìn)階9 數(shù)據(jù)存儲

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í)例變量

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ù)

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伪煤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凛辣,更是在濱河造成了極大的恐慌抱既,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扁誓,死亡現(xiàn)場離奇詭異防泵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蝗敢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門捷泞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寿谴,你說我怎么就攤上這事锁右。” “怎么了讶泰?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵咏瑟,是天一觀的道長。 經(jīng)常有香客問我峻厚,道長响蕴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任惠桃,我火速辦了婚禮浦夷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辜王。我一直安慰自己劈狐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布呐馆。 她就那樣靜靜地躺著肥缔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汹来。 梳的紋絲不亂的頭發(fā)上续膳,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天改艇,我揣著相機(jī)與錄音,去河邊找鬼坟岔。 笑死谒兄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的社付。 我是一名探鬼主播承疲,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸥咖!你這毒婦竟也來了燕鸽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤啼辣,失蹤者是張志新(化名)和其女友劉穎啊研,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸥拧,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悲伶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了住涉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡钠绍,死狀恐怖舆声,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柳爽,我是刑警寧澤媳握,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站磷脯,受9級特大地震影響蛾找,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赵誓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一打毛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俩功,春花似錦幻枉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔓罚,卻和暖如春椿肩,著一層夾襖步出監(jiān)牢的瞬間瞻颂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工郑象, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贡这,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓扣唱,卻偏偏與公主長得像藕坯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子噪沙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容