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表失败");
}

日常开发使用心得整理,如有纰漏,欢迎指正!!!

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