背景
在iOS開發(fā)中必不可少的要用到數(shù)據(jù)存儲,數(shù)據(jù)的處理是iOS開發(fā)中的核心技術(shù)娃磺,適當?shù)膶?shù)據(jù)進行持久化存儲可以實現(xiàn)應(yīng)用的離線功能薄湿,以此提高用戶體驗。所謂數(shù)據(jù)持久化偷卧,就是將數(shù)據(jù)保存到硬盤中豺瘤,使得在應(yīng)用程序或手機重啟后可以繼續(xù)訪問之前保存的數(shù)據(jù)。在iOS開發(fā)中听诸,有很多持久化得方案坐求,接下來我將總結(jié)以下5種持久化方案:
1、plist(屬性列表)
2晌梨、preference(偏好設(shè)置)
3桥嗤、NSKeyedArchiver(歸檔)
4、SQList 3 (FMDB)
5仔蝌、CoreData
應(yīng)用沙盒
在介紹各種存儲方法之前泛领,先說明下沙盒機制。每個iOS應(yīng)用都有一個 應(yīng)用沙盒「文件系統(tǒng)目錄」敛惊,與其他文件系統(tǒng)隔離
應(yīng)用必須在自己的沙盒里渊鞋,其他應(yīng)用不能訪問他人的沙盒
Documents:保存應(yīng)用運行時生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時會備份該目錄瞧挤。例如锡宋,游戲應(yīng)用可將游戲存檔保存在該目錄
tmp:保存應(yīng)用運行時所需的臨時數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除皿伺。應(yīng)用沒有運行時员辩,系統(tǒng)也可能會清除該目錄下的文件盒粮。iTunes同步設(shè)備時不會備份該目錄
Library/Caches:保存應(yīng)用運行時生成的需要持久化的數(shù)據(jù)鸵鸥,iTunes同步設(shè)備時不會備份該目錄。一般存儲體積大丹皱、不需要備份的非重要數(shù)據(jù)
Library/Preference:保存應(yīng)用的所有偏好設(shè)置妒穴,iOS的Settings(設(shè)置)應(yīng)用會在該目錄中查找應(yīng)用的設(shè)置信息。iTunes同步設(shè)備時會備份該目錄
// 獲取 Documents 文件路徑
// 方法一摊崭、利用沙盒根目錄拼接 ”Documents” 字符串
// 不建議采用讼油,因為新版本的操作系統(tǒng)可能會修改目錄名
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
// 方法二、利用 NSSearchPathForDirectoriesInDomains 函數(shù)
/**
NSSearchPathForDirectoriesInDomains
@param NSDocumentDirectory 搜索目錄是呢簸,Documents 目錄
@param NSUserDomainMask 搜索范圍是矮台,用戶文件夾
@param NO 不展開全路徑:~/Library/Caches
@return NSArray*
*/
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)firstObject];
NSLog(@"libraryPath = %@",libraryPath);
NSString *preferencePath =[libraryPath stringByAppendingString:@"/preferences"];
NSLog(@"%@",preferencePath);
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject];
NSLog(@"cachesPath = %@",cachesPath);
// 獲取 tmp 文件路徑
NSString *tmpPath = NSTemporaryDirectory();
plist(屬性列表)
iOS提供了一種plist格式的文件(屬性列表)用于存儲輕量級的數(shù)據(jù)乏屯,屬性列表是一種XML格式的文件,拓展名為plist。如果對象是NSString瘦赫、NSDictionary辰晕、NSArray、NSData類型,就可以使用writeToFile:atomically:?法 直接將對象寫到屬性列表文件中該格式保存的數(shù)據(jù)可以直接使用NSDictionary和NSArray讀取 确虱。plist文件在iOS開發(fā)中屬于Write寫入方式含友,可以以Property List列表形式顯示,也可以以xml格式顯示校辩。對于數(shù)據(jù)管理是很方便的窘问。掌握使用plist文件數(shù)據(jù)操作很有必要.
- NSString 寫入文件 讀取
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *filePath = [documentPath stringByAppendingPathComponent:@"str.txt"];
NSString *str = @"這是一個字符串";
//atomically是否進行線性操作(YES保證發(fā)生意外時有中轉(zhuǎn)文件來保存信息 直至寫入完成 但是損耗大. NO的時候?qū)懭胨俣瓤?但是沒有安全保障)
[str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSString *str1 = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//2017-03-19 15:28:09.740 信號量[3255:166796] 這是一個字符串
NSLog(@"%@",str1);
- NSArray 寫入文件 讀取
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *filePath = [documentPath stringByAppendingPathComponent:@"arr.txt"];
NSArray *array = @[@"abc",@"def",@"ghi"];
[array writeToFile:filePath atomically:YES];
NSArray *getArray = [NSArray arrayWithContentsOfFile:filePath];
// 2017-03-19 15:34:52.261 信號量[3423:172597] (
// abc,
// def,
// ghi
// )
NSLog(@"%@",getArray);
- NSDictionary 寫入文件 讀取
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *filePath = [documentPath stringByAppendingPathComponent:@"arr.txt"];
NSDictionary *dic = @{@"name":@"jack",@"age":@"13"};
[dic writeToFile:filePath atomically:YES];
NSDictionary *mydic = [NSDictionary dictionaryWithContentsOfFile:filePath];
// 2017-03-19 15:39:03.598 信號量[3479:176290] {
// age = 13;
// name = jack;
// }
NSLog(@"%@",mydic);
- NSData對象寫入 讀取
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *filePath = [documentPath stringByAppendingPathComponent:@"22.png"];
UIImage *image = [UIImage imageNamed:@"22.png"];
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:filePath atomically:YES];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
//2017-03-19 15:45:55.005 信號量[3666:183586] 3157
NSLog(@"%lu",(unsigned long)myData.length);
preference(偏好設(shè)置)
使用NSUserDefault 實現(xiàn)持久化
下面來看下 NSUserDefault 本地保存的位置,Library/Preferences 這個目錄下的 plist 文件就是其保存的目錄宜咒。
//1.獲得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中寫入內(nèi)容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.讀取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
偏好設(shè)置是專門用來保存應(yīng)用程序的配置信息的惠赫,一般不要在偏好設(shè)置中保存其他數(shù)據(jù)。
如果沒有調(diào)用synchronize方法故黑,系統(tǒng)會根據(jù)I/O情況不定時刻地保存到文件中汉形。所以如果需要立即寫入文件的就必須調(diào)用synchronize方法。
偏好設(shè)置會將所有數(shù)據(jù)保存到同一個文件中倍阐。即preference目錄下的一個以此應(yīng)用包名來命名的plist文件概疆。
NSKeyedArchiver(歸檔)
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
#import "Person.h"
//遵守NSCoding協(xié)議
@interface Person()<NSCoding>
@end
@implementation Person
#pragma mark 編碼,對象屬性進行編碼
- (void)encodeWithCoder:(NSCoder *)aCoder
{
//前者(_age,_name)是屬性,后者是關(guān)鍵字Key(age,name)
[aCoder encodeInt:_age forKey:@"age"];
[aCoder encodeObject:_name forKey:@"name"];
}
#pragma mark 解碼,解碼歸檔數(shù)據(jù)初始化對象
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
_age = [aDecoder decodeIntForKey:@"age"];
_name = [aDecoder decodeObjectForKey:@"name"];
}
return self;
}
@end
測試
NSArray *documentArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [documentArray firstObject];
NSLog(@"documentPath = %@",documentPath);
NSString *filePath = [documentPath stringByAppendingPathComponent:@"person"];
Person *p = [Person new];
p.name =@"wang";
p.age = 12;
//Encoding保存Person
[NSKeyedArchiver archiveRootObject:p toFile:filePath];
Person *pp = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
// 2017-03-19 16:32:16.750 信號量[4359:217706] wang
// 2017-03-19 16:32:16.751 信號量[4359:217706] 12
NSLog(@"%@",pp.name);
NSLog(@"%d",pp.age);
SQList 3和CoreData下篇再寫
SQList 3封裝 http://www.reibang.com/p/5471d001572c