本地持久化存储

一、沙盒机制

沙盒是什么

每个iOS应用都有属于自己的应用沙盒(沙盒就是文件系统目录),与其他文件系统隔离,每个应用都只能访问自己的沙盒。

沙盒的路径结构

  • Document:适合存储重要的数据, iTunes同步应用时会同步该文件下的内容,(比如游戏中的存档)
 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
  • Library/Caches:适合存储体积大,不需要备份的非重要数据,iTunes不会同步该文件
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
  • Library/Preferences: 通常保存应用的设置信息, iTunes同步该应用时会同步此文件夹中的内容
  • tmp:保存应用的临时文件,用完就删除,系统可能在应用没在运行时删除该目录下的文件,iTunes不会同步该文件
NSString *path = NSTemporaryDirectory();

获取沙盒路径

通过NSSearchPathForDirectoriesInDomains 方法来获取沙盒路径

二、数据存储常用方式

偏好设置(NSUserDefaults)

  • 偏好设置是专门保存应用的配置信息的,如用户名、密码等,一般不要在偏好设置中保存其他数据。
  • NSUserDefaults保存的数据都是不可变的,取出来的数据也是不可变类型,通过键值对方式进行存取。
  • 如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。
  • 偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。

实例如下:

//获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//保存内容
[userDefaults setValue:@"sunsan" forKey:username];
[userDefaults setValue:@"abcd1234" forKey:userpassword];
//读取内容
NSString * name = [userDefaults valueForKey:username];
NSString * password = [userDefaults valueForKey:userpassword];

plist存储

plist文件是将某些特定的类,通过XML文件的方式保存在目录中。
可以被序列化的类型有以下几种:

NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;

实例如下:

//设置文件名
NSString *fileName = [path stringByAppendingPathComponent:@"students.plist"];
//写入文件
[array writeToFile:fileName atomically:YES];
//读取
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];

归档解归档

通过使用NSKeyArchiverarchiveRootObject: toFile:方法直接归档一个对象,使用NSKeyedUnarchiverunarchiveObjectWithFile:解档对象。
在归档自定义对象的时候,必须遵守NSCoding协议,并实现协议方法:

  • 每次归档对象时,都会调用encodeWithCoder:,一般在这个方法里面指定如何归档对象中的每个实例变量;
  • 每次从文件中恢复对象时,都会调用initWithCoder:,一般在这个方法里面指定如何解码文件中的数据为对象的实例变量。

实例如下:

//设置文件名
NSString *fileName = [path stringByAppendingPathComponent:@"person.archiver"];
//进行归档
[NSKeyedArchiver archiveRootObject:per toFile:fileName];
//进行解归档
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:fileName];

以上的存储方法,都是覆盖存储。如果想要增加一条数据就必须把整个文件读出来,然后修改数据后再把整个内容覆盖写入文件,并不适合大量数据的存取。


SQLite

SQLite简介

SQLite是一个轻量级关系数据库,最初的设计目标是用于嵌入式系统,它占用资源非常少。在iOS中,只要导入libsqlite3.0.tbd依赖以及引入sqlite3.h头文件即可。
SQLite是无类型的数据库,可以保存任何类型的数据,对于SQLite来说对字段不指定类型是完全有效的

SQLite近似类似规则

  • 如果类型字符串中包含“int”,那么该字段的亲缘关系是INTEGER
  • 如果类型字符串中包含“char”,“clob”或“text”,那么该字段的亲缘类型是TEXT
  • 如果类型字符串中包含“blob”,那么该字段的亲缘类型是NONE
  • 如果类型字符串中包含“real”,“floa”或“doub”,那么该字段的亲缘类型是REAL
  • 其余情况下,字段的亲缘类型为NUMERIC

SQLite字段的约束条件

  • not null —— 非空
  • unique —— 唯一
  • primary key —— 主键
  • foreign key —— 外键
  • check —— 条件检查,确保一列中所有的值满足一定条件
  • default —— 默认
  • autoincrement —— 自增型变量,该字段数据如果为整形可以自动加1

SQLite语句

SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。

  • DML主要包含数据的增删改:
    数据插入(insert):insert into 表名(字段1,字段2,……)values(字段1值,字段2值,……)
    数据更新(update):update 表名 set 字段1=修改值1,字段2=修改值2,……where 条件
    数据删除(delete):delete from 表名 where 条件
  • DQL主要用于查询获得表中的数据,其中差用的关键字包含where,order by,group by和having
    数据查询(select):select 查找字段 from 表名 where 条件
  • DDL部分包含创建或者删除表格,定义索引,规定表之间的链接,以及施加表间的约束
    建表命令:create table if not exists 表名(字段1 约束1 约束2……,字段2 约束1 约束2)
    删表命令:drop table if exists 表名

FMDB

FMDB是一款轻量级的框架,以OC的方式对SQLite的C语言API进行封装,对多线程并发进行处理,所以线程安全。

FMDB常用类

FMDatabase:一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句
FMResultSet:使用FMDatabase执行查询后的结果集
FMDatabaseQueue:用于在多线程中执行多个查询或更新,它是线程安全的

FMDB操作

  • 使用FMDataBase类建立数据库
//获取Documents路径
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject ;
//生成数据库路径
NSString *filePath = [path stringByAppendingPathComponent:@"person.sqlite"];
//获取数据库
database = [FMDatabase databaseWithPath:filePath];
if ([database open]) {
    NSLog(@"数据库打开成功");
}else{
    NSLog(@"打开数据库失败");
}
  • 表的创建
BOOL result = [database executeUpdate:@"create table if not exists person (name text primary key not null, city text, age integer)"];
if (result) {
    NSLog(@"创建表成功");
} else {
    NSLog(@"创建表失败");
}
  • 添加数据
BOOL result = [database executeUpdate:@"insert into person (name,city,age) values (?,?,?)",per.name,per.city,@(per.age)];
if (result) {
    NSLog(@"添加数据成功");
} else {
    NSLog(@"添加数据失败");
}
  • 删除数据
BOOL result = [database executeUpdate:@"delete from person where name = ?",per.name];
if (result) {
    NSLog(@"删除数据成功");
} else {
    NSLog(@"删除数据失败");
}
  • 修改数据
BOOL result = [database executeUpdate:@"update person set city = ?,age = ? where name = ?",per.city,@(per.age),per.name];
if (result) {
    NSLog(@"修改数据成功");
} else {
    NSLog(@"修改数据失败");
}
  • 查询所有数据
FMResultSet *result = [database executeQuery:@"select * from person"];
while ([result next]) {
    Person *per = [[Person alloc] init];
    per.name = [result stringForColumn:@"name"];
    per.city = [result stringForColumn:@"city"];
    per.age =  [result intForColumn:@"age"];
     [array addObject:per];
}
  • 关闭数据库
if ([database close]) {
    NSLog(@"关闭数据库成功");
} else {
    NSLog(@"关闭数据库失败");
}

参考:完整项目资料下载

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容