目錄
一、沙盒
* 每個iOS應用程序都有自己獨立的存儲空間,此區域稱爲沙盒。應用只在自己的沙盒中操作,其它應用程序無法訪問該沙盒。
* 數據持久化就是將數據存儲到沙盒中。
* 數據持久化操作的沙盒文件目錄:
文件夾 | 備份 | 使用 |
---|---|---|
Douments | YES |
使用此目錄保存用戶數據,該目錄的內容可以通過文件共享提供給用戶,因此這裏存儲希望向用戶公開的文件。可以是用戶創建、導入、刪除或編輯的任何文件,例如:繪圖類APP用戶可能創建的任何圖形文件;文本編輯類APP產生的文本文件;視頻、音頻類APP用戶下載後的視頻、音頻文件。 因爲Documents/中的文件默認情況下是會備份的,任何可以重新創建或下載的文件都必須從備份中排出,特別是大型媒體文件,例如:視頻APP下載的視頻、音樂APP下載的歌曲。可以用調用下面方法來排除:-[NSURL setResourceValue:forKey:error:] ,其中key用 NSURLIsExcludedFromBackupKey 。 |
Library |
YES(除Caches外) |
這是所有非用戶數據的頂級目錄。希望被備份但不希望用戶看到的數據,例如APP的默認設置或其它狀態信息。系統在Library目錄下創建了Catches和Preferences兩個子目錄,通常直接使用這兩個子目錄,也可以創建自定義的子目錄。 |
Library/Preferences | YES |
包含了存儲應用程序偏好設置的plist文件,通過NSUserDefaults來讀寫。 |
Library/Caches | NO |
緩存數據,可以保存任何比臨時數據(tmp中存儲的數據)持久時間更長的數據,一般來說,APP沒有緩存數據也要能正常運行,但它可以使用緩存數據來提高性能。因爲系統可能會刪除緩存數據來釋放磁盤空間。 |
tmp | NO |
臨時數據,可以保存任何在APP運行期間需要的臨時數據,當不再需要時應及時刪除,這樣不會繼續佔用用戶設備上的空間,應用程序不運行時系統會定期清除這些文件。 |
Documents路徑:
NSString *documentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
Library路徑:
NSString *libraryDirectory = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject;
Preferences使用
NSUserDefaults *userDufaults = [NSUserDefaults standardUserDefaults];
Caches路徑
NSString *catchesDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
tmp路徑
NSString *tmpDirectory = NSTemporaryDirectory();
二、數據持久化方式
* 常用幾種數據持久化方式對比
持久化方式 | 使用 |
---|---|
屬性列表plist |
1、用來存儲少量數據 2、無法將自定義對象序列化到屬性列表中,只能存儲下列數據類型: NSNumber NSDate NSData/NSMutableData NSArray/NSMutableArray NSDictionary/NSMutableDictionary NSString/NSMutableString |
NSUserDefaults |
1、用來存儲少量數據,一般用來保存應用配置信息 2、使用簡單,但數據保存位置固定(都保存在Preferences文件夾下以應用包命名的plist文件) 3、無法將自定義對象序列化到屬性列表中 |
對象歸檔 |
1、用來存儲少量數據。(解檔時會一次性全部取出文件中內容,存儲大型數據會比較消耗資源) 2、彌補了前兩種方式無法存儲自定義類的不足,能存儲遵循NSCoding協議的自定義對象 |
FMDB | 1、數據庫,存儲複雜的數據 |
* 屬性列表plist
//待存數據
NSArray *array = @[@"A",@"B",@"C"];
//Documents文件夾路徑
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
//待存文件路徑
NSString *fileName = [documentPath stringByAppendingPathComponent:@"TestData.plist"];
//如果是新建文件路徑,可以先判斷創建的文件路徑是否已經存在了,避免數據被覆蓋。
NSFileManager *fileManage = [NSFileManager defaultManager];
if ([fileManage fileExistsAtPath:fileName]) {
NSLog(@"已經存在TestData.plist文件");
}else{
NSLog(@"存在TestData.plist文件");
}
//寫入。(atomically:YES 先創建一個輔助文件,如果寫入成功再把輔助文件寫入目標地址,更安全,因爲如果在寫入過程中程序崩潰了,原文件(如果有)不會被破壞,只是效率會低一些,一般都用YES;反之不安全但效率高。)
BOOL writeSuccess = [array writeToFile:fileName atomically:YES];
if (writeSuccess) {
NSLog(@"寫入成功");
}
//讀取
NSArray *arr = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"plist:%@",arr);
* 偏好設置Preference
//用NSUserDefaults操作
NSUserDefaults *userDufaults = [NSUserDefaults standardUserDefaults];
//寫入
[userDufaults setBool:YES forKey:@"isCloss"];
//NSUserDefaults是定時把緩存中的數據寫入磁盤的,而不是即時寫入,爲了防止在寫完NSUserDefaults後程序退出導致的數據丟失,可以在寫入數據後使用synchronize強制立即將數據寫入磁盤
[userDufaults synchronize];
//讀取
BOOL isCloss = [userDufaults boolForKey:@"isCloss"];
* 對象歸檔(以下只例舉了自定義類的歸檔方法)
/*
* PeopleModel.h
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PeopleModel : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger ID;
@end
NS_ASSUME_NONNULL_END
/*
* PeopleModel.m
*/
#import "PeopleModel.h"
@implementation XMPeopleModel
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInteger:_age forKey:@"age"];
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInteger:_ID forKey:@"ID"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.ID = [aDecoder decodeIntegerForKey:@"ID"];
}
return self;
}
/*
歸檔實現代碼
*/
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [documentPath stringByAppendingPathComponent:@"people.plist"];
XMPeopleModel *peopleModel = [[XMPeopleModel alloc] init];
peopleModel.name = @"Tony";
peopleModel.age = 28;
//歸檔
if ([NSKeyedArchiver archiveRootObject:peopleModel toFile:filePath]) {
NSLog(@"Tony 歸檔成功");
}
//反歸檔
XMPeopleModel *people = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
* FMDB(基本方法示例)
//創建database路徑
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *dbPath = [documentPath stringByAppendingPathComponent:@"fmdb.sqlite"];
//創建對應路徑下的數據庫
db_ = [FMDatabase databaseWithPath:dbPath];
//打開數據庫
if ([db_ open]) {
NSLog(@"打開數據庫成功!");
}else{
NSLog(@"打開數據庫失敗");
}
//數據庫中創建表(可創建多張)
NSString *createSql = @"CREATE TABLE IF NOT EXISTS t_people (name text NOT NULL,age integer NOT NULL);";//b如果不存在t_people表,就創建該表。
if ([db_ executeUpdate:createSql]) {
NSLog(@"t_people表創建成功");
}else{
NSLog(@"t_people表創建失敗");
}
//待存數據
XMPeopleModel *peopleA = [[XMPeopleModel alloc] init];
peopleA.name = @"Amy";
peopleA.age = 19;
XMPeopleModel *peopleB = [[XMPeopleModel alloc] init];
peopleB.name = @"Tony";
peopleB.age = 29;
//插入數據
BOOL resultA = [db_ executeUpdate:@"INSERT INTO t_people (name,age) VALUES (?,?)" withArgumentsInArray:@[peopleA.name,@(peopleA.age)]];
//[db_ executeUpdateWithFormat:@"INSERT INTO t_people (name,age) VALUES (%@,%ld)",peopleA.name,(long)peopleA.age];
if (resultA) {
NSLog(@"Amy插入成功");
}else {
NSLog(@"Amy插入失敗");
}
BOOL resultB = [db_ executeUpdateWithFormat:@"INSERT INTO t_people (name,age) VALUES (%@,%ld)",peopleB.name,(long)peopleB.age];
if (resultB) {
NSLog(@"Tony插入成功");
}else {
NSLog(@"Tony插入失敗");
}
//更新數據
BOOL updateResult = [db_ executeUpdate:@"UPDATE t_people SET name = ? WHERE name = ?",@"Tony2",@"Tony"];
if (updateResult) {
NSLog(@"Tony名字改成Tony2");
}else{
NSLog(@"Tony改名失敗");
}
//刪除數據
BOOL deleteResult = [db_ executeUpdate:@"DELETE FROM t_people WHERE name = ?",@"Tony"];
if (deleteResult) {
NSLog(@"刪除Tony成功");
}else{
NSLog(@"刪除Tony失敗");
}
//查詢數據
FMResultSet *resultSet = [db_ executeQuery:@"SELECT * FROM t_people"];//查詢整個表
while ([resultSet next]) {
NSString *name = [resultSet stringForColumn:@"name"];
NSInteger age = [resultSet intForColumn:@"age"];
NSLog(@"%@今年%ld歲了",name,(long)age);
}
FMResultSet *resultSetTony = [db_ executeQuery:@"SELECT * FROM t_people WHERE name = ?",@"Tony"];//根據條件查詢
while ([resultSetTony next]) {
NSString *TonyName = [resultSetTony stringForColumn:@"name"];
NSInteger TonyAge = [resultSetTony intForColumn:@"age"];
NSLog(@"%@老師%ld大壽",TonyName,TonyAge);
}
//銷燬表
BOOL dropResult = [db_ executeUpdate:@"DROP TABLE IF EXISTS t_people"];
if (dropResult) {
NSLog(@"刪除t_people表");
}else{
NSLog(@"未能刪除t_people表");
}
* FMDB(單例用法示例)
/*
單例 XMDataBase.h
*/
#import <Foundation/Foundation.h>
#import "PeopleModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface XMDataBase : NSObject
+ (instancetype)shareInstance;
//增
- (BOOL)addPerson:(PeopleModel *)person;
//刪
- (BOOL)deletePersonWithID:(NSInteger)ID;
//改
- (BOOL)updatePerson:(PeopleModel *)person;
//查
- (NSArray *)getAllPeople;
- (PeopleModel *)getPersonWithID:(NSInteger)ID;
//銷燬
- (BOOL)dropTable:(NSString *)tableName;
@end
NS_ASSUME_NONNULL_END
/*
單例 XMDataBase.m
*/
#import "XMDataBase.h"
#import "FMDB/FMDB.h"
@interface XMDataBase()
{
FMDatabase *db_;
}
@end
@implementation XMDataBase
+ (instancetype)shareInstance {
static XMDataBase *dataBase = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataBase = [[super allocWithZone:nil] init];
[dataBase initDataBase];
});
return dataBase;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [XMDataBase shareInstance];
}
- (id)copy {
return [XMDataBase shareInstance];
}
- (id)mutableCopy {
return [XMDataBase shareInstance];
}
- (void)initDataBase {
//document路徑
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//創建文件路徑
NSString *filePath = [documentPath stringByAppendingPathComponent:@"people.sqlite"];
//創建對應路徑下的數據庫
db_ = [FMDatabase databaseWithPath:filePath];
//打開數據庫
if ([db_ open]) {
NSLog(@"打開數據庫成功");
//創建表
NSString *creatSql = @"CREATE TABLE IF NOT EXISTS t_people(id integer NOT NULL, name text NOT NULL,age integer NOT NULL)";
if ([db_ executeUpdate:creatSql]) {
NSLog(@"創建數據表t_people成功");
}else {
NSLog(@"創建數據表t_people失敗");
}
[db_ close];
}else {
NSLog(@"打開數據庫失敗");
}
}
#pragma mark 增
- (BOOL)addPerson:(PeopleModel *)person {
[db_ open];
NSString *insertSql = @"INSERT INTO t_people(id,name,age) VALUES(?,?,?)";
BOOL result = [db_ executeUpdate:insertSql,@(person.ID),person.name,@(person.age)];
[db_ close];
return result;
}
#pragma mark 刪
- (BOOL)deletePersonWithID:(NSInteger)ID {
[db_ open];
NSString *deleteSql = @"DELETE FROM t_people WHERE id=?";
BOOL result = [db_ executeUpdate:deleteSql,@(ID)];
[db_ close];
return result;
}
#pragma mark 改
- (BOOL)updatePerson:(PeopleModel *)person {
[db_ open];
NSString *updateSql = @"UPDATE t_people SET %@ = ? WHERE id = ?";
BOOL resultName = [db_ executeUpdate:[NSString stringWithFormat:updateSql,@"name"],person.name,@(person.ID)];
BOOL resultAge = [db_ executeUpdate:[NSString stringWithFormat:updateSql,@"age"],@(person.age),@(person.ID)];
[db_ close];
return resultName&&resultAge;
}
#pragma mark 查(獲取整張表)
- (NSArray *)getAllPeople {
[db_ open];
NSMutableArray *allPeople = [NSMutableArray array];
NSString *selectSql = @"SELECT *FROM t_people";
FMResultSet *resultSet = [db_ executeQuery:selectSql];
while ([resultSet next]) {
PeopleModel *peopleModel = [[XMPeopleModel alloc] init];
peopleModel.ID = [resultSet intForColumn:@"ID"];
peopleModel.name = [resultSet objectForColumn:@"name"];
peopleModel.age = [resultSet intForColumn:@"age"];
[allPeople addObject:peopleModel];
}
[db_ close];
return allPeople;
}
#pragma mark 查(根據條件查詢)
- (XMPeopleModel *)getPersonWithID:(NSInteger)ID {
[db_ open];
NSString *selectSql = @"SELECT *FROM t_people WHERE id = ?";
FMResultSet *resultSet = [db_ executeQuery:selectSql,@(ID)];
while ([resultSet next]) {
NSInteger resultID = [resultSet intForColumn:@"id"];
if (ID == resultID) {
PeopleModel *person = [[XMPeopleModel alloc] init];
person.ID = ID;
person.name = [resultSet objectForColumn:@"name"];
person.age = [resultSet intForColumn:@"age"];
[db_ close];
return person;
}
}
[db_ close];
return nil;
}
#pragma mark 銷燬表
- (BOOL)dropTable:(NSString *)tableName {
[db_ open];
NSString *dropSql = @"DROP TABLE IF EXISTS t_people";
BOOL result = [db_ executeUpdate:dropSql];
[db_ close];
return result;
}
@end
/*
XMDataBase單例使用示例
*/
PeopleModel *amy = [[PeopleModel alloc] init];
amy.ID = 2;
amy.name = @"Amy";
amy.age = 18;
BOOL addResult = [[XMDataBase shareInstance] addPerson:amy];
if (addResult) {
NSLog(@"Amy添加成功");
}else{
NSLog(@"Amy添加失敗");
}
BOOL deleteResult = [[XMDataBase shareInstance] deletePersonWithID:2];
if (deleteResult) {
NSLog(@"刪除Amy成功");
}else{
NSLog(@"刪除Amy失敗");
}
amy.age = 19;
BOOL updateResult = [[XMDataBase shareInstance] updatePerson:amy];
if (updateResult) {
NSLog(@"Amy的age更新成功");
}else{
NSLog(@"Amy的age更新失敗");
}
//根據條件(ID)獲取表中特定數據
PeopleModel *Amy = [[XMDataBase shareInstance] getPersonWithID:2];
NSLog(@"name:%@ age:%ld id:%ld",Amy.name,Amy.age,Amy.ID);
//獲取整張表
NSArray *arr = [[XMDataBase shareInstance] getAllPeople];
for (PeopleModel *model in arr) {
NSLog(@"name:%@ age:%ld id:%ld",model.name,model.age,model.ID);
}
BOOL dropResult = [[XMDataBase shareInstance] dropTable:@"t_people"];
if (dropResult) {
NSLog(@"刪除t_people表成功");
}else{
NSLog(@"刪除t_people表失敗");
}
日常開發使用心得整理,如有紕漏,歡迎指正!!!