NO.1前言
1正塌、iOS應(yīng)用數(shù)據(jù)存儲(chǔ)的常用方式
- XML屬性列表(plist)歸檔
- Preference(偏好設(shè)置)
- NSKeyedArchiver歸檔(NSCoding)
- SQLite3 <數(shù)據(jù)庫(kù)>
- Core Data
NO2.操做
1、應(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
2粒褒、應(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è)置讲弄,iOS的Settings(設(shè)置)應(yīng)用會(huì)在該目錄中查找應(yīng)用的設(shè)置信息护戳。iTunes同步設(shè)備時(shí)會(huì)備份該目錄
3、應(yīng)用沙盒目錄的常見(jiàn)獲取方式
// 獲取沙盒路徑
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:是否展開(kāi)全路徑 YES:表示展開(kāi)全路徑 NO:不會(huì)展開(kāi)全路徑,會(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è)置信息
// 寫(xiě)入
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
// [userDefaults setBool:NO forKey:@"jhyes"];
// [userDefaults setObject:@"ljh" forKey:@"name"];
[userDefaults setValue:@"JHL" forKey:@"NAME"];
// 數(shù)據(jù)持久化
[userDefaults synchronize];
// 9 讀取
NSUserDefaults *redDef = [NSUserDefaults standardUserDefaults];
// BOOL result = [redDef boolForKey:@"jhyes"];
// NSString *result = [redDef objectForKey:@"name"];
NSString *result = [redDef valueForKey:@"NAME"];
NSLog(@"result = %@", result);
}
4赏壹、偏好設(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"];
讀取:
// 利用NSUserDefaults單例
NSString *pwd = [[NSUserDefaults standardUserDefaults] objectForKey:@"pwd"];
NSInteger i = [[NSUserDefaults standardUserDefaults] integerForKey:@"num"];
5、屬性列表
- 1 plist存儲(chǔ),生成一個(gè)plist文件.
- 2 plist不是數(shù)組就是字典,plist存儲(chǔ)就是用來(lái)存儲(chǔ)字典或者數(shù)組.
注意:Plist不能存儲(chǔ)自定義對(duì)象
- 3 屬性列表是一種XML格式的文件酬荞,拓展名為plist
- 4 如果對(duì)象是
NSString搓劫、NSDictionary、NSArray混巧、NSData枪向、NSNumber
等類型,就可以使用writeToFile:atomically:
方法直接將對(duì)象寫(xiě)到屬性列表文件中
// 寫(xiě)入:
// 將一個(gè)NSDictionary對(duì)象歸檔到一個(gè)plist屬性列表
// 將數(shù)據(jù)封裝成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"coderLee" forKey:@"name"];
[dict setObject:@"13903058421" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 將字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
// 讀取:
// 讀取屬性列表咧党,恢復(fù)NSDictionary對(duì)象
[dict dictionaryWithContentsOfFile:path];
6秘蛔、NSData
- 使用archiveRootObject:toFile:方法可以將一個(gè)對(duì)象直接寫(xiě)入到一個(gè)文件中,但有時(shí)候可能想將多個(gè)對(duì)象寫(xiě)入到同一個(gè)文件中傍衡,那么就要使用NSData來(lái)進(jìn)行歸檔對(duì)象
- NSData可以為一些數(shù)據(jù)提供臨時(shí)存儲(chǔ)空間缠犀,以便隨后寫(xiě)入文件,或者存放從磁盤(pán)讀取的文件內(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];
// 開(kāi)始存檔對(duì)象虐急,存檔的數(shù)據(jù)都會(huì)存儲(chǔ)到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存檔完畢(一定要調(diào)用這個(gè)方法)
[archiver finishEncoding];
// 將存檔的數(shù)據(jù)寫(xiě)入文件
[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專門(mén)用來(lái)做自定義對(duì)象歸檔
[NSKeyedArchiver archiveRootObject:p toFile:filePath];
在person.m
// 什么時(shí)候調(diào)用:當(dāng)一個(gè)對(duì)象要?dú)w檔的時(shí)候就會(huì)調(diào)用這個(gè)方法歸檔
// 作用:告訴蘋(píng)果當(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è)方法解檔
// 作用:告訴蘋(píng)果當(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;
}
總結(jié)
1被辑、數(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è)文件夾俄删。
2宏怔、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> 如何寫(xiě)入到沙盒蔬胯,需要獲取沙盒路徑。
- 獲取Documents路徑
- 拼接文件名约谈,因?yàn)閿?shù)據(jù)是寫(xiě)入到文件中笔宿,不是寫(xiě)入到文件夾中。路徑之間通過(guò)/分開(kāi)的棱诱,為了避免自己寫(xiě)/泼橘,會(huì)用stringByAppendingPathCompent,自動(dòng)在文件夾與文件之間添加/迈勋。
- 4> 如何讀取炬灭,存儲(chǔ)是什么類型存儲(chǔ),讀取出來(lái)也是什么類型靡菇,直接用存儲(chǔ)的類型重归,解析文件就好,用ContentsOfFile解析厦凤。
- 5> 注意plist存儲(chǔ)鼻吮,不能存儲(chǔ)自定義對(duì)象,會(huì)失敗的较鼓。
3椎木、偏好設(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ù)同步到硬盤(pán)上。
- 4> 怎么利用偏好設(shè)置讀取?
和字典一樣,根據(jù)剛剛存儲(chǔ)的Key讀取猎醇。
4窥突、自定義對(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,重寫(xiě)initWithCoder方法裆馒,一定要調(diào)用[super initWithCoder:],因?yàn)橹挥邢到y(tǒng)才知道怎么解析storyboard丐怯,如果沒(méi)有調(diào)用喷好,就解析不了這個(gè)文件。