iOS 常用幾種數據持久化

目錄

一、沙盒

二、數據持久化方式

* 常用幾種數據持久化方式對比

* 屬性列表plist

* 偏好設置Preference

 * 對象歸檔(以下只例舉了自定義類的歸檔方法)

* FMDB(基本方法示例)

* FMDB(單例用法示例)


一、沙盒

點擊查看iOS應用程序文件系統官方文檔

應用程序的沙盒目錄結構

 

* 每個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表失敗");
}

日常開發使用心得整理,如有紕漏,歡迎指正!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章