什么是數(shù)據(jù)持久化?
概論
所謂的持久化,就是將數(shù)據(jù)保存到硬盤中,使得在應(yīng)用程序或機(jī)器重啟后可以繼續(xù)訪問之前保存的數(shù)據(jù)。在iOS開發(fā)中,有很多數(shù)據(jù)持久化的方案,接下來我將嘗試著介紹一下5種方案:
plist文件(屬性列表)
preference(偏好設(shè)置)
NSKeyedArchiver(歸檔)
SQLite 3
CoreData
沙盒
在介紹各種存儲方法之前,有必要說明以下沙盒機(jī)制。iOS程序默認(rèn)情況下只能訪問程序自己的目錄,這個目錄被稱為“沙盒”.
//沙盒主路徑
//程序運(yùn)行期間,系統(tǒng)會生成一個專屬的沙盒路徑,應(yīng)用程序在使用期間的非代碼文件都存儲在當(dāng)前的沙盒路徑里面
NSArray *documentPathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSLog(@"%@",documentPathArray);
//第一個參數(shù):要查詢文件的路徑
//第二個參數(shù):要查詢路徑所屬的用戶(iOS為單用戶)
//第三個參數(shù):YES是絕對路徑,NO是相對路徑
#pragma mark library 用于保存程序運(yùn)行期間生成的語言
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)firstObject];
NSLog(@"libraryPath = %@",libraryPath);
#pragma mark caches文件 用于保存程序運(yùn)行期間產(chǎn)生緩存文件
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject];
NSLog(@"cachesPath%@",cachesPath);
#pragma mark Preferences 文件夾 用來保存程序偏好設(shè)置
//
// NSString *preferencePath = [NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES)firstObject];
//
// NSLog(@"preferences%@",preferencePath);
寫入文件(plist文件)
#pragma mark --NSString 寫入文件
//1.準(zhǔn)備字符串
// NSString *string = @"I love my iOS teacher's phone";
//
// //2.準(zhǔn)備路徑
//
// NSString *path = NSHomeDirectory();
// path = [path stringByAppendingString:@"/咒語.txt"];
//3.寫入文件
// [string writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
//第一個參數(shù):路徑
//第二個參數(shù):是否進(jìn)行線性操作(yes的時候,保證發(fā)生意外時,有中轉(zhuǎn)文件保存信息,直至寫入完成,但是損耗大,no的時候,寫入速度快,但是沒有安全保障)
//第三個參數(shù):編碼方式
//第四個參數(shù):錯誤對象
//4.打印path
// NSLog(@"%@",path);
// //5讀取文件
// //第一個參數(shù):路徑
// //第二個參數(shù):編碼方式:(切記要和寫入時用的相同的編碼方式)
// //第三個參數(shù):錯誤信息
//
// NSString *contentString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// NSLog(@"%@",contentString);
同樣的簡單對象(NSString,NSArray,NSDictionary;NSData)我們都可以用這種方法寫入文件來實(shí)現(xiàn)數(shù)據(jù)持久化.
#pragma mark NSData 寫入文件
// //1獲取圖片對象
// UIImage *image = [UIImage imageNamed:@"image1.png"];
//
// //2.準(zhǔn)備路徑
// NSString *homePath = NSHomeDirectory();
// homePath = [homePath stringByAppendingPathComponent:@"image1.png"];
// //將圖片對象轉(zhuǎn)化成data
//
// NSData *data = UIImagePNGRepresentation(image);
//
// [data writeToFile:homePath atomically:YES];
// //讀取圖片
// UIImageView *imgView = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
// imgView.image = [UIImage imageWithContentsOfFile:homePath];
//
// [self.view addSubview:imgView];
復(fù)雜對象寫入文檔(歸檔)
#pragma mark ---- 復(fù)雜對象寫入文件
SingleVip *vip = [SingleVip new];
vip.name = @"法特";
vip.assets = @"數(shù)不清";
vip.car = @"蘭博基尼";
vip.age = 18;
NSString *homePath = NSHomeDirectory();
homePath = [homePath stringByAppendingPathComponent:@"鉆石王老五.txt"];
//創(chuàng)建數(shù)據(jù)對象,用來存放vip對象
NSMutableData *data = [NSMutableData data];
//創(chuàng)建歸檔對象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
//開始?xì)w檔
[archiver encodeObject:vip forKey:@"vip"];
//完成歸檔
[archiver finishEncoding];
//寫入文件
[data writeToFile:homePath atomically:YES];
NSLog(@"%@",homePath);
//反歸檔
//將文件里面的data對象讀取出來
NSData *_data = [NSData dataWithContentsOfFile:homePath];
//創(chuàng)建反歸檔對象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:_data];
SingleVip *_vip = [unarchiver decodeObjectForKey:@"vip"];
//完成反歸檔
[unarchiver finishDecoding];
NSLog(@"%@",_vip.name);
SingleVip.h
#import <Foundation/Foundation.h>
@interface SingleVip : NSObject<NSCoding>
@property(nonatomic,strong)NSString *name;
@property(nonatomic,strong)NSString *assets;//資產(chǎn)
@property(nonatomic,strong)NSString *car;
@property(nonatomic,assign)int age;
SingleVip.m
#import "SingleVip.h"
#define KName @"name"
#define KAssets @"assets"
#define KAge @"age"
#define KCar @"car"
@implementation SingleVip
- (void)encodeWithCoder:(NSCoder *)aCoder{
//編碼
[aCoder encodeObject:_name forKey:KName];
[aCoder encodeObject:_assets forKey:KAssets];
[aCoder encodeObject:_car forKey:KCar];
[aCoder encodeInt:_age forKey:KAge];
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
//反編碼
_name = [aDecoder decodeObjectForKey:KName];
_assets = [aDecoder decodeObjectForKey:KAssets];
_car = [aDecoder decodeObjectForKey:KCar];
_age = [aDecoder decodeIntForKey:KAge];
}
return self;
}
歸檔并不是數(shù)據(jù)持久化,而是輔助復(fù)雜對象轉(zhuǎn)化成簡單對象的一種方式,真正實(shí)現(xiàn)數(shù)據(jù)持久化的仍然是writeToFile寫入文件
SQLite
關(guān)于SQLite的開發(fā)資料較多,這里不再細(xì)說。只是建議不直接操作SQLite庫,而是采用一些開源的第三方庫來進(jìn)行操作。比如:FMDB:https://github.com/ccgus/fmdb.git對SQLite都做了不錯的封裝。