首先談一下自己對iOS中數(shù)據(jù)持久化這個概念的理解鲁僚。所謂的數(shù)據(jù)持久化就是將數(shù)據(jù)保存在本地硬盤中扰魂,這樣即使我們的應(yīng)用退出后再次重啟時依然能夠拿到之前保存的數(shù)據(jù)。要談數(shù)據(jù)存儲方式首先我們需要了解一下Bundle和沙盒的含義:
Bundle:應(yīng)用程序在手機中的安裝路徑
沙盒:存儲app所有的數(shù)據(jù)的路徑
接下來我們就來實際地看看每個app的bundle和沙盒的地址蕴茴,其實也是我一直想弄清楚的東西劝评,它們其實都在個人用戶下的隱藏文件夾下,以自己創(chuàng)建的工程StepSlider這個工程為例:
沙盒的結(jié)構(gòu)為:
1. Documents : 保存持久化數(shù)據(jù)倦淀,會備份
2. Library : 1. Caches : 保存持久化數(shù)據(jù)蒋畜,不會備份
2. Preferences : 保存持久化數(shù)據(jù),會備份
3. tmp : 保存臨時文件
以上每個目錄對應(yīng)的獲取方式:
{
Documents: NSDocumentDirectory
Library: NSLibraryDirectory
Caches: NSCachesDirectory
}
// 1.要查找的文件夾 2.從用戶文件夾查找 3.展開目錄~ 4.得到的結(jié)果是個數(shù)組
舉例:NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
有個問題是我一直想搞清楚的撞叽,這里為什么最后要加[0]姻成?因為還函數(shù)返回的是一個NSArray,且因為每個app應(yīng)用的沙盒地址是唯一的愿棋,因此該數(shù)組僅有一個元素科展,所以可以取第一個元素[0]或者lastObject來獲取
tmp: NSString *tmp = NSTemporaryDirectory();
數(shù)據(jù)存儲的常用方式主要有以下5種:
1. plist(屬性列表)文件 -- 用到文件路徑
2. Preference(偏好設(shè)置) -- 無需文件路徑
3. NSKeyedArchiver(歸檔/解檔) -- 用到文件路徑
4. SQLite(FMDB:基于SQLite3 封裝的一套OC的API庫)
5. Core Data
第一種方式:plist
plist文件中存儲的數(shù)據(jù)都是不需要加密,數(shù)據(jù)量小糠雨,簡單的數(shù)據(jù)才睹,plist文件只能存儲NSArray和NSDictionary
- (void)setUpPlist{
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [path stringByAppendingString:@"/dyf.plist"];
NSLog(@"filePath======%@",filePath);
NSDictionary *dic = @{
@"name":@"duyingfeng",
@"age":@25,
@"height":@1.75f,
@"weight":@55
};
[dic writeToFile:filePath atomically:YES];
NSDictionary *dic1 = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSLog(@"dic1=====%@",dic1);
}
我們來看一下實際運行效果:
總結(jié)起來plist存儲和讀取過程可以通過一張圖來看清:
第二種方式:Preference(偏好設(shè)置)
Preference(偏好設(shè)置)通常是用來存儲應(yīng)用的一些配置信息的,比如:保存用戶的用戶名甘邀,密碼琅攘,文本格式等設(shè)置,通過NSUserDefaults來存取偏好設(shè)置
- (void)setUpSaveUserDefaults {
//獲取NSUserDefaults對象,是個單例
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//存儲數(shù)據(jù)
[defaults setObject:@"dyf" forKey:@"name"];
[defaults setBool:YES forKey:@"isCool"];
[defaults setInteger:25 forKey:@"age"];
[defaults setDouble:1.75f forKey:@"height"];
//強制立刻存儲
[defaults synchronize];
}
- (void)setUpReadUserDefaults {
//獲取NSUserDefaults對象
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//讀取數(shù)據(jù)
NSString *name = [defaults objectForKey:@"name"];
BOOL isCool = [defaults boolForKey:@"isCool"];
NSInteger age = [defaults integerForKey:@"age"];
double height = [defaults doubleForKey:@"height"];
NSLog(@"name=%@,isCool=%d,age=%ld,height=%.2f",name,isCool,(long)age,height);
}
運行完成后松邪,存儲文件位置以及日志輸出結(jié)果
第三種方式:NSKeyedArchiver歸檔
只有遵守了NSCoding協(xié)議的對象才可以歸檔和解檔坞琴,所有系統(tǒng)的對象都可以直接歸檔解檔。而自定義對象必須手動遵守協(xié)議并且實現(xiàn)歸檔方法和解檔方法
encodeWithCoder 和 initWithCoder
1.對于系統(tǒng)的類:
- (void)systemEncodeAndDecode{
NSArray *array = @[@111,@222,@333];
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *newPath = [path stringByAppendingString:@"/dyf.plist"];//這里的后綴可以任意嗎
[NSKeyedArchiver archiveRootObject:array toFile:newPath];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithFile:newPath];
NSLog(@"取出數(shù)組為====%@",arr);
}
插入圖片====
2.對于自定義的類
//歸檔
- (void)saveStudentData{
LPDStudent *stu = [[LPDStudent alloc] init];
stu.name = @"duyingfeng";
stu.age = 18;
stu.height = 1.75f;
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *newPath = [path stringByAppendingString:@"/stu.plist"];
[NSKeyedArchiver archiveRootObject:stu toFile:newPath];
}
//解檔
- (void)readStudentData{
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *newPath = [path stringByAppendingString:@"/stu.plist"];
LPDStudent *stu1 = [NSKeyedUnarchiver unarchiveObjectWithFile:newPath];
NSLog(@"name-%@,age-%d,height-%.2f",stu1.name,stu1.age,stu1.height);
}
插入圖片===
3.對于多個對象
使用archiveRootObject:toFile:方法可以將一個對象直接寫入到一個文件中逗抑,但有時候可能想將多個對象寫入到同一個文件中剧辐,那么就要使用NSData來進行歸檔對象
例如:將兩個Person對象存入同一文件中
//歸檔
- (void)saveMutableStudentData{
LPDStudent *stu1 = [[LPDStudent alloc] init];
stu1.name = @"一號";
stu1.age = 13;
stu1.height = 1.55f;
LPDStudent *stu2 = [[LPDStudent alloc] init];
stu2.name = @"二號";
stu2.age = 20;
stu2.height = 1.90f;
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:stu1 forKey:@"stu1"];
[archiver encodeObject:stu2 forKey:@"stu2"];
[archiver finishEncoding];
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *newPath = [path stringByAppendingString:@"/mutable.plist"];
[data writeToFile:newPath atomically:YES];
}
//解檔
- (void)readMutableStudentData{
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *newPath = [path stringByAppendingString:@"/mutable.plist"];
NSData *data = [NSData dataWithContentsOfFile:newPath];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
LPDStudent *stu1 = [unarchiver decodeObjectForKey:@"stu1"];
LPDStudent *stu2 = [unarchiver decodeObjectForKey:@"sut2"];
[unarchiver finishDecoding];
NSLog(@"stu1===%@,%d,%.2f",stu1.name,stu1.age,stu1.height);
NSLog(@"stu2===%@,%d,%.2f",stu2.name,stu2.age,stu2.height);
}
插入圖片=====