数据存储 内存存储 常见的内存缓存框架有: `NSCache`、`TMMemoryCache`、 `PINMemoryCache`、`YYMemoryCache`。 适合高频访问,内存占用小的 ,非持久化数据,断电后丢失。 NSCache 苹果提供的一个简单的内存缓存,它有着和 `NSDictionary` 类似的 API 它是线程安全的 YYMemoryCache 内部用`双向链表`和 `NSDictionary` 实现了 `LRU 淘汰算法`(Least recently used,最近最少使用) 1. APP会优先请求内存缓冲中的资源 2. 如果内存缓冲中有,则直接返回资源文件, 如果没有的话,则会请求资源文 件,这时资源文件可能存储在服务端,需要进行网络请求获取,也可以是本地文 件,需要操作文件系统或数据库来获取。 3. 获取到的资源文件,先缓存到内存缓存,方便以后不再重复获取,节省时间。 4. 然后就是从缓存中取到数据然后给app使用。 内存警告 内存警告时需要释放一些占用空间大,当前不再使用的数据 磁盘 存储 持久化的文件,信息等 分为两大类: 文件系统存储和数据库系统存储 文件系统: 把数据组织成相互独立的数据文件。 整体无结构 适合文件大,特异,无关联 数据库系统: 整体数据的结构化, 管理数据库的存储,事务,以及对数据库的操作 适合小,杂,多,排序,查询等 文件系统存储 存储方案有`plist文件存储`,`NSUserDefalut存储`,`keyChain存储`, `NSKeyedArchiver`(序列化存储),NSData plist文件 一些hc代码,固定配置,key-value 形式存储 本质是XML文件 NSUserDefaults存储 plist文件可视化编辑,如果使用代码读取,那么使用 NSUserDefaults 存取 本质: 本质是管理plist 文件,系统提供这个管理类,方便存取 优点: `NSUserDefaults`会将`plist`文件的数据读取到缓存中,因此访问速度会很快 注意: 1.存储系统类型,不能是自定义 2.不能是可变集合或者可变对象 KeyChain 安全: 是一个安全的存储容器,所以非常适合保存一些敏感信息到设备中 位置: 数据保持在系统中,但是又在app沙盒之外。 因此app卸载后重新安装数据还在,除非更新系统 共享: 通过`keychain access groups`可以在不同应用之间共享`keychain`中的数 据。 要求在保存数据到`keychain`的时候指定`group`。 公司其它多app账号授权互通 位置: `KeyChain`数据保存的地方是一个`sqlite数据库` 位于`/private/var/Keychains/keychain-2.db` 用户不需要关系数据库操作 数据是加密的 NSKeyedArchiver 前面说过,NSUserDefaults 可以存储系统一些数据类型,不可变,非自定义 的。 @interface NSKeyedArchiver : NSCoder NSKeyedArchiver 就可以存储几乎绝大部分数据类型 归档,或者叫 序列化 遵循协议: 自定义类需要遵循对应协议,系统不用 NSCoding: 不可变对象遵循 NSMutableCoding:可变对象code协议 调用方法:NSKeyedArchiver - encode xx - (void)encodeObject:(nullable id)object forKey:(NSString *)key; - (void)encodeConditionalObject:(nullable id)object forKey:(NSString *)key; - (void)encodeBool:(BOOL)value forKey:(NSString *)key; 【 encodeXX : Int,Int32,Int64,Float,Double,Bytes】 解档,或者叫 反序列化 NSKeyedUnarchiver - decode 方法 - (nullable id)decodeObjectForKey:(NSString *)key; - (BOOL)decodeBoolForKey:(NSString *)key; - (int)decodeIntForKey:(NSString *)key; // may raise a range exception - (int32_t)decodeInt32ForKey:(NSString *)key; - (int64_t)decodeInt64ForKey:(NSString *)key; - (float)decodeFloatForKey:(NSString *)key; - (double)decodeDoubleForKey:(NSString *)key; 小结: `NSKeyedArchiver`非常适合把一个自定义的对象序列化后存储到文件系统中去 NSData 直接利用系统函数,把数据保存到指定的文件目录下。 图片,歌曲,视频一般都是通过这种形式存储的。 数据库 基本概念 database 用来存储容器,对外可见 .db 文件 Table 存放具体数据的容器,key-value形式 CREATE TABLE `CLOTHES` ( `key` int(11) NOT NULL AUTO_INCREMENT, `value` char(255) NOT NULL DEFAULT '', PRIMARY KEY (`k`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 id:唯一序号 通常表数据可以增删改查,排序等等 SQL 操作表格数据的语句,增删改查 命令或语句 关系型数据库 数据以二维表格形式存储,并通过对多个表格进行分类、合并、连接或选取等运 算来实现数据库的管理。 服务端: 常见有`Oracle`和`MySQL` 移动端: 最常用的SQlite 非关系型数据库 在超大规模和高并发的SNS类型的web2.0纯动态网站中有着非常好的性能 NoSQL: (NoSQL = Not Only SQL ),意即“不仅仅是SQL”, 泛指非关系型数据库。 非关系型数据库 又分为: 键值存储数据库(key-value)(比如Redis数据库)、 列存储(Column-oriented)数据库、 面向文档(Document-Oriented)数据库、 图形数据库。 服务端特别互联网时代,对非关系行数据库有非常广泛的应用。 在移动端有代表性的: Realm(跨平台) ACID 是指数据库管理系统(`DBMS`)在写入或更新资料的过程中,为保证事务 (`transaction`)是正确可靠的,所必须具备的四个特性: 原子性(`atomicity`,或称不可分割性)、 一致性(`consistency`)、 隔离性(`isolation`,又称独立性)、 持久性(`durability`)。 Sqlite 特点 关系型数据库 轻型的数据库 遵守`ACID`的关系型数据库管理系统 跨平台 sql流程 一个对Employee表的数据操作流程如下: 1. SQL语句 -> 2. 触发磁盘I/O -> 3.磁盘返回一个表对应的`Index`表【索引】的一页Page, 包含若干条记录 -> 4. 在上述记录当中找到目标记录,如果没有找到 满足条件的记录,则循环第2步骤和第3步骤, 直到找到满足条件的记录-> 5.根据`Index`表的记录里存放的`position`信息 找到原始表记录的位置 -> 6.对原始表当中的目标记录进行操作,完成SQL操作。 原理 Core层 1接口层 2编译器 语法分析 词法分析 代码生成 3虚拟机 Backend层 4.B-Tree (B 树) 5.Pager 6.OS 接口 database 辅助功能 Accessories Backend层的辅助层: Accessories 包括:工具类Utils 和测试代码 Test Code 业务原理 SQLite由很多部分组成-parser,tokenize,virtual machine等等。 但是从程序员的角度,最需要知道的是:connection, statements, B-tree和 pager。 它们之间的关系如下: 三个主要方面:API,事务(Transaction)和锁(Locks)。从技术上来说,B-tree和 pager不是API的一部分 一个独立的事务(Transaction) 环境有一个连接(Connection), 一个连接对应 多个statement。 每一个statement都和一个connection关联,它通常表示一个编译过的SQL语 句,在内部,它以VDBE字节码表示。 Statement包括执行一个命令所需要一切,包括保存VDBE程序执行状态所需的资 源,指向硬盘记录的B-树游标,以及参数等等 B-tree和pager: 一个connection可以有多个database对象---一个主要的数据库以及附加的数据 库,每一个数据库对象有一个B-tree对象,一个B-tree有一个pager对象(这里的 对象不是面向对象的“对象”,只是为了说清楚问题) Statement最终都是通过connection的B-tree和pager从数据库读或者写数据, 通过B-tree的游标(cursor)遍历存储在页面(page)中的记录。游标在访问页面之 前要把数所从disk加载到内存,而这就是pager的任务。任何时候,如果B-tree 需要页面,它都会请求pager从disk读取数据,然后把页面(page)加载到页面缓 冲区(page cache),之后,B-tree和与之关联的游标就可以访问位于page中的记 录了。 如果cursor改变了page,为了防止事务回滚,pager必须采取特殊的方式保存原 来的page。总的来说,pager负责读写数据库,管理内存缓存和页面(page), 以及管理事务,锁和崩溃恢复(这些在事务一节会详细介绍). 执行流程 1. 连接数据库(Connect to the database) 2.执行事务(Perform transactions) 3.断开连接(Disconnect from the database) 代码片段: //打开数据 rc = sqlite3_open("foods.db", &db); //关闭数据库 sqlite3_close(db); 磁盘I/O瓶颈 一次查询往往无法通过一次I/O 操作完成。所以如何减少磁盘I/O 的次数成为我 们优化`SQlite`性能的关键 内存页 内存和磁盘中的数据存储和交互都是以页(page)为单位的。即使内存只需要1 个字节的数据,从磁盘读取的时候也是拿到一个或多个`Page`,这是系统级别的 一种预先缓存策略 索引表 内存按页分段数据,一页能包含数据条数有限,因此,大量查询 结果的数据关系 就用到索引了 映射原表来记录key索引字段表 :索引表 B树 二叉树的高度会过大,而矮胖树结构便于 磁盘IO,尽量减小原始表的大小,避免 因树过于庞大