iOS技术点

【重读iOS】数据持久化2:持久化方案介绍

2018-09-17  本文已影响37人  FindCrt

什么是数据持久化

内存在断点后就会清空重置,为了保持数据在断点后保持,比如手机重启,就需要把数据存放在硬盘里,做持久化的保存。为什么不一直使用硬盘保存,因为内存会比硬盘更快速。所以在程序的声明周期里,数据加载在内存里,进行快速的计算,然后把需要持久保存的数据保存到硬盘里。

数据持久化就是怎么把数据存储到硬盘里的技术,准确的说,存储是硬件干的事,而对软件而言,关键任务是组织和识别。就是一块数据,你怎么识别为你需要的内容,比如4个字节,可以是一个int数字,也可以是4个字符。所以关键是找到一种格式把数据组织好,存入硬盘,然后按对应的方式再识别。

计算机里有很多地方都是这个逻辑,如音视频的编解码,HTTP请求的数据解析,传输或存储之前都要有一个组织和识别的过程。

方式

  1. plist文件
  2. 归档Archive
  3. 数据库

有了上面的理解,再看这些,不同方式的区别也就是组织数据的方式的区别

plist文件本质是一个xml文件,xml文件可以很好的定义层级关系,用字典和数组互相嵌套定义一个复杂的结构。

归档这个内部不知道是怎么实现的,但一般配合NSKeyedArchiver使用,几次对encodeWithCoder:initWithCoder:的使用情况来看,有几点可以推测:

然后数据库是更复杂的结构,应对大量数据的处理。上面两种方式最大问题是它们的修改都是整体修改,一张很大的plist文件里的某一个小部分的修改,也需要把整个文件读取,修改然后再整个重新写入,所以对于数据量大和修改频繁的情况,前两种不好。

plist文件和归档对比

@interface Book : NSObject<NSCoding>

@property (nonatomic) NSString *name;
@property (nonatomic) NSString *name1;
@property (nonatomic) NSString *name2;
@property (nonatomic) NSString *name3;

@end

建一个类,使用归档方式写入文件,然后使用字典模拟这个类的结构,把字典写入plist文件,对比两个文件:

1个对象 10个 100个 1000个
归档 259 733 5477 52128
plist 374 2300 21290 211190

相比之下,归档文件要小很多,但从10-100-1000对比看,貌似还是和plist文件一样,都是线性增长。

照着这个思路,只要找到一种描述对象内存的方式,就可以按这种方式组织内存,然后写入文件里,就可以设计一种新的持久化方案。最简单的,使用json描述对象,然后把json文件写入硬盘。神奇的是在这个例子里,10000个对象后,json文件比归档还小!!!

数据库

sqlite原生操作

  1. 建库

    sqlite3_open一句搞定,没有文件的会自动创建

  2. 建表

执行SQL语句create table 表名称 (列名1 列类型1, 列名2 列类型2)

列名有5种基本类型:

INTEGER 根据值的大小会自动变化,数据库中只有一个表,表中就一个列为INTEGER时,1000条数据时,值全部为1(1个字节)时数据库文件为25k,值为1LL<<60(8个字节)时为33k,可以说很明显了。

读取的时候提供了sqlite3_column_intsqlite3_column_int64两个方法来指定长度读取。

亲和类型

除了5大基本类型外,在建表的时候可以写入其他类型,会根据亲和类型,把你写入的类型转到基本类型来存储。比如常见的char(20),这个是TEXT的亲和类型,数据库内部实际按TEXT存储,但建表的时候可以char(20)这么写。

列的亲和类型

  1. 插入数据

insert into 表名称 (列名1,列名2) values (值1,值2)
然后执行sql语句就可以了。

注意:不指定列名时表示对所有列都插入数据;值是字符串类型的要使用引号包括起来;

  1. 查询数据

select * from 表名称,或者指定查询的列select 列名1,列名2 from 表名称

然后后面可以接查询条件:

where子语句
  1. 更新数据

update Book set 列名1 = 值1, 列名2 = 值2 [条件语句]
一种方式值直接把值写入sql语句里,然后执行,还有一种是在值的位置填入问号?,然后使用sqlite3_bind系列的函数绑定数据,具体操作示例:

sqlite3_stmt *stmt;
   sqlite3_prepare_v2(dbHanle, [updateSql cStringUsingEncoding:NSUTF8StringEncoding], (int)updateSql.length, &stmt, nil);
   //1
   sqlite3_bind_text(stmt, 1, [book.name cStringUsingEncoding:NSUTF8StringEncoding], book.name.length, nil);
  sqlite3_bind_int64(stmt, 2, book.age);
   sqlite3_step(stmt);
   //2
   sqlite3_finalize(stmt);

位置1到2之间可循环操作多条数据。

  1. 删除数据

delete from 表名称 [条件语句],然后执行sql语句

  1. 事务

使用事务的好处:

事务和多线程

  1. 表信息
  1. 表修改
上一篇 下一篇

猜你喜欢

热点阅读