1坤次、iOS應(yīng)用數(shù)據(jù)存儲(chǔ)的常用方式
- XML屬性列表(plist)歸檔
- Preference(偏好設(shè)置)
- NSKeyedArchiver歸檔(NSCoding)
- SQLite3
- Core Data
2、應(yīng)用沙盒
每個(gè)iOS應(yīng)用都有自己的應(yīng)用沙盒(應(yīng)用沙盒就是文件系統(tǒng)目錄)斥赋,與其他文件系統(tǒng)隔離缰猴。應(yīng)用必須待在自己的沙盒里,其他應(yīng)用不能訪問(wèn)該沙盒
應(yīng)用沙盒的文件系統(tǒng)目錄疤剑,如下圖所示(假設(shè)應(yīng)用的名稱叫Layer)
模擬器應(yīng)用沙盒的根路徑在: (apple是用戶名, 8.0是模擬器版本)
/Users/apple/Library/Application Support/iPhone Simulator/8.0/Applications
3滑绒、應(yīng)用沙盒結(jié)構(gòu)分析
應(yīng)用程序包:(上圖中的Layer)包含了所有的資源文件和可執(zhí)行文件
Documents
:保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)會(huì)備份該目錄隘膘。例如疑故,游戲應(yīng)用可將游戲存檔保存在該目錄
tmp
:保存應(yīng)用運(yùn)行時(shí)所需的臨時(shí)數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除弯菊。應(yīng)用沒(méi)有運(yùn)行時(shí)纵势,系統(tǒng)也可能會(huì)清除該目錄下的文件。iTunes同步設(shè)備時(shí)不會(huì)備份該目錄
Library/Caches
:保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)不會(huì)備份該目錄钦铁。一般存儲(chǔ)體積大扫茅、不需要備份的非重要數(shù)據(jù)
Library/Preference
:保存應(yīng)用的所有偏好設(shè)置,NSUserDefaults的數(shù)據(jù)存放于此目錄下,iOS的Settings(設(shè)置)應(yīng)用會(huì)在該目錄中查找應(yīng)用的設(shè)置信息育瓜。iTunes同步設(shè)備時(shí)會(huì)備份該目錄
4葫隙、plist文件
1.plist存儲(chǔ),生成一個(gè)plist文件.
2.plist不是數(shù)組就是字典,plist存儲(chǔ)就是用來(lái)存儲(chǔ)字典或者數(shù)組.
注意:Plist不能存儲(chǔ)自定義對(duì)象
5、應(yīng)用沙盒目錄的常見獲取方式
// 獲取沙盒路徑
1躏仇、NSHomeDirectory()
2恋脚、tmp:NSString *tmp = NSTemporaryDirectory();
3、Library/Caches:(跟Documents類似的2種方法)
利用沙盒根目錄拼接”Caches”字符串
利用NSSearchPathForDirectoriesInDomains函數(shù)(將函數(shù)的參數(shù)改為:NSCachesDirectory即可)
// directory:獲取哪個(gè)文件夾
// domainMask:在哪個(gè)范圍內(nèi)搜索,NSUserDomainMask:表示在用戶的手機(jī)上查找
// expandTilde:是否展開全路徑 YES:表示展開全路徑 NO:不會(huì)展開全路徑,會(huì)把應(yīng)用沙盒的路徑用波浪號(hào)(~)代替
// 獲取到Caches文件夾路徑
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 拼接文件名
NSString *filePath = [cachePath stringByAppendingPathComponent:@"arr.plist"];
// 1焰手、存儲(chǔ)plist,File:文件的全路徑
[arr writeToFile:filePath atomically:YES];
// 2糟描、讀取plist,之前是什么類型存儲(chǔ)的,讀取也是什么
NSArray *arr = [NSArray arrayWithContentsOfFile:filePath];
4、Library/Preference:通過(guò)NSUserDefaults類存取該目錄下的設(shè)置信息
6书妻、屬性列表
屬性列表是一種XML格式的文件船响,拓展名為plist
如果對(duì)象是NSString、NSDictionary躲履、NSArray见间、NSData、NSNumber等類型工猜,就可以使用writeToFile:atomically:方法直接將對(duì)象寫到屬性列表文件中7米诉、屬性列表-歸檔NSDictionary
將一個(gè)NSDictionary對(duì)象歸檔到一個(gè)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];
- 8、屬性列表-恢復(fù)NSDictionary
讀取屬性列表篷帅,恢復(fù)NSDictionary對(duì)象
- 9史侣、偏好設(shè)置
很多iOS應(yīng)用都支持偏好設(shè)置,比如保存用戶名魏身、密碼惊橱、字體大小等設(shè)置,iOS提供了一套標(biāo)準(zhǔn)的解決方案來(lái)為應(yīng)用加入偏好設(shè)置功能
每個(gè)應(yīng)用都有個(gè)NSUserDefaults實(shí)例箭昵,通過(guò)它來(lái)存取偏好設(shè)置
比如税朴,保存用戶名、字體大小宙枷、是否自動(dòng)登錄
以字典的形式進(jìn)行偏好設(shè)置,用法跟字典一樣.
偏好設(shè)置好處: 1.不需要關(guān)心文件名 2.快速進(jìn)行鍵值對(duì)存儲(chǔ) 3.直接存儲(chǔ)基本數(shù)據(jù)類型
保存:
// 獲取單例
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// @"123" key:pwd
[defaults setObject:@"123" forKey:@"pwd"];
// bool
[defaults setBool:YES forKey:@"isOn"];
// int
[defaults setInteger:10 forKey:@"num"];
讀取也很簡(jiǎn)單
// 利用NSUserDefaults單例
NSString *pwd = [[NSUserDefaults standardUserDefaults] objectForKey:@"pwd"];
NSInteger i = [[NSUserDefaults standardUserDefaults] integerForKey:@"num"];
- 10掉房、NSData
使用archiveRootObject:toFile:方法可以將一個(gè)對(duì)象直接寫入到一個(gè)文件中,但有時(shí)候可能想將多個(gè)對(duì)象寫入到同一個(gè)文件中慰丛,那么就要使用NSData來(lái)進(jìn)行歸檔對(duì)象
NSData可以為一些數(shù)據(jù)提供臨時(shí)存儲(chǔ)空間,以便隨后寫入文件瘾杭,或者存放從磁盤讀取的文件內(nèi)容诅病。可以使用[NSMutableData data]創(chuàng)建可變數(shù)據(jù)空間
(圖)
1)NSData-歸檔2個(gè)Person對(duì)象到同一文件中
歸檔(編碼)
// 新建一塊可變數(shù)據(jù)區(qū)
NSMutableData *data = [NSMutableData data];
// 將數(shù)據(jù)區(qū)連接到一個(gè)NSKeyedArchiver對(duì)象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 開始存檔對(duì)象,存檔的數(shù)據(jù)都會(huì)存儲(chǔ)到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存檔完畢(一定要調(diào)用這個(gè)方法)
[archiver finishEncoding];
// 將存檔的數(shù)據(jù)寫入文件
[data writeToFile:path atomically:YES];
2)NSData-從同一文件中恢復(fù)2個(gè)Person對(duì)象
恢復(fù)(解碼)
// 從文件中讀取數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfFile:path];
// 根據(jù)數(shù)據(jù)贤笆,解析成一個(gè)NSKeyedUnarchiver對(duì)象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
// 恢復(fù)完畢
[unarchiver finishDecoding];
3)利用歸檔實(shí)現(xiàn)深復(fù)制
比如對(duì)一個(gè)Person對(duì)象進(jìn)行深復(fù)制
// 臨時(shí)存儲(chǔ)person1的數(shù)據(jù)
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];
// 解析data蝇棉,生成一個(gè)新的Person對(duì)象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
// 分別打印內(nèi)存地址
NSLog(@"person1:0x%x", person1); // person1:0x7177a60
NSLog(@"person2:0x%x", person2); // person2:0x7177cf0
歸檔:
存儲(chǔ)自定義對(duì)象
Person *p = [[Person alloc] init];
p.age = 18;
p.name = @"a";
// 獲取tem文件夾路徑
NSString *tempPath = NSTemporaryDirectory();
// 拼接文件名
NSString *filePath = [tempPath stringByAppendingPathComponent:@"person.data"];
// NSKeyedArchiver專門用來(lái)做自定義對(duì)象歸檔
[NSKeyedArchiver archiveRootObject:p toFile:filePath];
在person.m
// 什么時(shí)候調(diào)用:當(dāng)一個(gè)對(duì)象要?dú)w檔的時(shí)候就會(huì)調(diào)用這個(gè)方法歸檔
// 作用:告訴蘋果當(dāng)前對(duì)象中哪些屬性需要?dú)w檔
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInt:_age forKey:@"age"];
}
解檔:
// 獲取tem文件夾路徑
NSString *tempPath = NSTemporaryDirectory();
// 拼接文件名
NSString *filePath = [tempPath stringByAppendingPathComponent:@"person.data"];
// 解檔
Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
什么時(shí)候調(diào)用:當(dāng)一個(gè)對(duì)象要解檔的時(shí)候就會(huì)調(diào)用這個(gè)方法解檔
// 作用:告訴蘋果當(dāng)前對(duì)象中哪些屬性需要解檔
// initWithCoder什么時(shí)候調(diào)用:只要解析一個(gè)文件的時(shí)候就會(huì)調(diào)用
- (id)initWithCoder:(NSCoder *)aDecoder
{
#warning [super initWithCoder]
// 這里不能用[super initWithCoder],什么時(shí)候調(diào)用[super initWithCoder:aDecoder]:只要父類遵守了NSCoding協(xié)議,就調(diào)用
if (self = [super init]) {
// 解檔
// 注意一定要記得給成員屬性賦值
_name = [aDecoder decodeObjectForKey:@"name"];
_age = [aDecoder decodeIntForKey:@"age"];
}
return self;
}
11.數(shù)據(jù)存儲(chǔ)(數(shù)據(jù)持久化)
1> 介紹iOS數(shù)據(jù)存儲(chǔ)的5種方式
2> 介紹應(yīng)用沙盒(應(yīng)用程序的文件夾)
? 如何找到應(yīng)用沙盒的路徑芥永?首先需要顯示隱藏文件篡殷。
? 點(diǎn)擊前往->個(gè)人->資源庫(kù)->Application Support->iPhone Simulator->7.1->里面全是應(yīng)用沙盒
3> 應(yīng)用沙盒怎么多文件夾保存,在哪個(gè)文件夾埋涧。介紹沙盒里的每一個(gè)文件夾板辽。
12.plist存儲(chǔ)
? 把一些系統(tǒng)自帶的OC對(duì)象生成pilst文件存儲(chǔ)起來(lái)。
1> 了解數(shù)據(jù)存儲(chǔ):數(shù)據(jù)存儲(chǔ)一般有兩個(gè)操作棘催,一個(gè)存劲弦,一個(gè)取。拖兩個(gè)按鈕醇坝,一個(gè)用來(lái)存邑跪,一個(gè)用來(lái)取
2> plist存儲(chǔ)原理:
? 只要有writeToFile的對(duì)象,就能進(jìn)行plist存儲(chǔ)呼猪,調(diào)用writeToFile就能自動(dòng)生成plist格式的文件画畅。
? 一般常用的Foundation對(duì)象都有這個(gè)方法,數(shù)組宋距,字典夜赵,字符串等
3> 如何寫入到沙盒,需要獲取沙盒路徑乡革。
? 獲取Documents路徑
? 拼接文件名寇僧,因?yàn)閿?shù)據(jù)是寫入到文件中,不是寫入到文件夾中沸版。路徑之間通過(guò)/分開的嘁傀,為了避免自己寫/,會(huì)用stringByAppendingPathCompent视粮,自動(dòng)在文件夾與文件之間添加/细办。
4> 如何讀取,存儲(chǔ)是什么類型存儲(chǔ)蕾殴,讀取出來(lái)也是什么類型笑撞,直接用存儲(chǔ)的類型,解析文件就好钓觉,用ContentsOfFile解析茴肥。
5> 注意plist存儲(chǔ),不能存儲(chǔ)自定義對(duì)象荡灾,會(huì)失敗的瓤狐。
13> 偏好設(shè)置
1> 什么是偏好設(shè)置存儲(chǔ):就是保存一些基本的信息瞬铸,賬號(hào),密碼础锐,狀態(tài)嗓节。
2> 偏好設(shè)置原理:不需要關(guān)心文件名,直接通過(guò)NSUserDefaults操作皆警,默認(rèn)就存到偏好設(shè)置里面了拦宣。
? 通過(guò)NSUserDefaults就能直接訪問(wèn)軟件的偏好設(shè)置(Library/Preferences)
3> 怎么利用偏好設(shè)置存儲(chǔ)?利用NSUserDefaults調(diào)用setObject:forKey存儲(chǔ)。
? 偏好設(shè)置底層實(shí)現(xiàn)原理:底層其實(shí)就是利用一個(gè)字典信姓,存儲(chǔ)一些鍵值對(duì)鸵隧。
? 偏好設(shè)置好處:能快速存儲(chǔ)一些鍵值對(duì),如果用字典去存儲(chǔ)财破,還需要獲取文件名比較麻煩掰派。
? 偏好設(shè)置壞處:不能及時(shí)存儲(chǔ),需要做同步操作左痢,把內(nèi)存中的數(shù)據(jù)同步到硬盤上靡羡。
4> 怎么利用偏好設(shè)置讀取?和字典一樣,根據(jù)剛剛存儲(chǔ)的Key讀取俊性。
14> 自定義對(duì)象歸檔(歸檔:數(shù)據(jù)存儲(chǔ))
1> 自定義對(duì)象如何歸檔:用NSKeyedArchiver,調(diào)用archiveRootObject:toFile:方法略步,需要傳一個(gè)對(duì)象,自定義一個(gè)對(duì)象定页,傳進(jìn)去趟薄。
? 會(huì)報(bào)錯(cuò),說(shuō)對(duì)象沒(méi)有encodeWithCoder方法,說(shuō)明歸檔的時(shí)候默認(rèn)會(huì)調(diào)用這個(gè)方法典徊,去實(shí)現(xiàn)這個(gè)方法杭煎。
? 默認(rèn)打不出encodeWithCoder,必須遵守NSCoding協(xié)議才能實(shí)現(xiàn)這個(gè)方法卒落。
? encodeWithCoder什么時(shí)候調(diào)用:對(duì)象歸檔時(shí)候調(diào)用
? encodeWithCoder作用:告訴系統(tǒng)對(duì)象里的哪些屬性需要?dú)w檔羡铲,怎么去歸檔,根據(jù)一個(gè)key去歸檔儡毕,目的就是以后取的時(shí)候也切,也根據(jù)這個(gè)key去取數(shù)據(jù)。
2> 自定義對(duì)象如何解檔:用NSKeyedUnarchiver,調(diào)用unarchiveObjectWithFile方法腰湾,需要傳一個(gè)文件名雷恃。
? 會(huì)報(bào)錯(cuò),說(shuō)對(duì)象沒(méi)有initWithCoder方法,說(shuō)明解檔的時(shí)候默認(rèn)會(huì)調(diào)用這個(gè)方法费坊,去實(shí)現(xiàn)這個(gè)方法倒槐。
? initWithCoder什么時(shí)候調(diào)用:對(duì)象解檔時(shí)候調(diào)用
? initWithCoder作用:告訴系統(tǒng)對(duì)象里的哪些屬性需要解檔,怎么去解檔葵萎,根據(jù)之前存儲(chǔ)的key去解檔
? initWithCoder是一個(gè)初始化方法导犹,需要先初始化父類的唱凯,但是不能調(diào)用[super initWithCoder:],因?yàn)楦割怤SObject沒(méi)有遵守NSCoding協(xié)議羡忘。
3> initWithCoder什么時(shí)候需要調(diào)用[super initWithCoder:]
? initWithCoder原理:只要解析文件就會(huì)調(diào)用谎痢,xib,storyboard都是文件,因此只要解析這兩個(gè)文件卷雕,就會(huì)調(diào)用initWithCoder节猿。
? 因此如果在storyboard使用自定義view,重寫initWithCoder方法,一定要調(diào)用[super initWithCoder:]漫雕,因?yàn)橹挥邢到y(tǒng)才知道怎么解析storyboard滨嘱,如果沒(méi)有調(diào)用,就解析不了這個(gè)文件浸间。
轉(zhuǎn)載: iOS開發(fā)——UI進(jìn)階篇(十一)應(yīng)用沙盒太雨,歸檔,解檔魁蒜,偏好設(shè)置囊扳,plist存儲(chǔ),NSData兜看,自定義對(duì)象歸檔解檔