iOS数据存储的四种方案对比

你是用什么方法来持久保存数据的?这是在几乎每一次关于iOS技术的交流或讨论都会被提到的问题,并且你们对这个问题的热情持续高涨。本文主要从概念上把“数据存储”这个问题进行剖析,而且结合各自特色和适用场景给你们提供一个选择的思路,并不详细介绍某一种方式的技术细节。html

谈到数据储存,首先要明确区分两个概念,数据结构和储存方式。所谓数据结构就是数据存在的形式。除了基本的NSDictionary、NSArray和NSSet这些对象,还有更复杂的如:关系模型、对象图和属性列表多种结构。而存储方式则简单的分为两种:内存与闪存。内存存储是临时的,运行时有效的,但效率高,而闪存则是一种持久化存储,但产生I/O消耗,效率相对低。把内存数据转移到闪存中进行持久化的操做称成为归档。数据库

两者结合起来才是完整的数据存储方案,咱们最常谈起的那些:SQLite、CoreData、NSUserDefaults等都是数据存储方案。固然在这些框架提供的方案以外,咱们本身也能够按照个性化需求订制方案。这些存储方案侧重不一样,支持的形式和方式也各不相同,在不一样的使用场景下表现也是各有优劣。但万变不离其宗,不管什么方案均可以用下图来解释。数组

\

图1,存储方案示意图缓存

如下将对四种存储方式进行详细的介绍:数据结构

  • NSUserDefaults,用于存储配置信息
  • SQLite,用于存储查询需求较多的数据
  • CoreData,用于规划应用中的对象
  • 使用基本对象类型定制的个性化缓存方案

用NSUserDefaults存储配置信息架构

NSUserDefaults被设计用来存储设备和应用的配置信息,它经过一个工厂方法返回默认的、也是最经常使用到的实例对象。这个对象中储存了系统中用户的配置信息,开发者能够经过这个实例对象对这些已有的信息进行修改,也能够按照本身的需求建立新的配置项。框架

\

图2,笔者手机中[NSUserDefaults standardUserDefaults]内容ide

NSUserDefaults把配置信息以字典的形式组织起来,支持字典的项包括:字符串或者是数组,除此以外还支持数字等基本格式。一句话归纳就是:基础类型的小数据的字典。操做方法几乎与NSDictionary的操做方法无异,另外还能够经过指定返回类型的方法获取到指定类型的返回值。性能

\

图3,NSUserDefaults提供的指定返回类型的方法列表spa

NSUserDefaults的全部数据都放在内存里,所以操做速度很快,并还提供一个归档方法:+ (void)synchronize。开发者自定义的配置项(如图2中的最后一项 key:alkdjfkladsjfmm)会以plist格式的文件归档在相应应用目录的/Library/Preferences/[App_Bundle_Identifier].plist文件。再次初始化得到实例对象后,框架会把用户自定义的这个配置和系统配置合并获得完整数据。

用SQLite存储查询需求较多的数据

iOS的SDK里预置了SQLite的库,开发者能够自建SQLite数据库。SQLite每次写入数据都会产生IO消耗,把数据归档到相应的文件。

SQLite擅长处理的数据类型其实与NSUserDefaults差很少,也是基础类型的小数据,只是从组织形式上不一样。开发者能够以关系型数据库的方式组织数据,使用SQL DML来管理数据。 通常来讲应用中的格式化的文本类数据能够存放在数据库中,尤为是相似聊天记录、Timeline等这些具备条件查询和排序需求的数据。

每个数据库的句柄都会在内存中都会被分配一段缓存,用于提升查询效率。另外一个方面,因为查询缓存,当产生大量句柄或数据量较大时,会出现缓存过大,形成内存浪费。

SQLite的使用起来要比NSUserDefaults复杂的多,所以建议开发者使用SQLite要搭配一个操做控件使用,能够简化操做。笔者开发的SQLight是一款对SQLite操做的封装,把相对复杂的SQLite命令封装成对象和方法,能够供你们参考。你们能够在Github上获取这个工程的代码进一步了解。

用CoreData规划应用中对象

官方给出的定义是,一个支持持久化的,对象图和生命周期的自动化管理方案。严格意义上说CoreData是一个管理方案,他的持久化能够经过SQLite、XML或二进制文件储存。如官方定义所说,CoreData的做用远远不止储存数据这么简单,它能够把整个应用中的对象建模并进行自动化的管理。

\

图4,官方文档中解释CoreData给出的对象图示例

正如上图所示,MyDocument是一个对象实例,有两个Collection:Employee和Department,存放各自的对象列表。MyDocument、Employee和Department三个对象以及他们之间的关系都经过CoreData建模,并能够经过save方法进行持久化。

从归档文件还原模型时CoreData并非一次性把整个模型中的全部数据都载入内存,而是根据运行时状态,把被调用到的对象实例载入内存。框架会自动控制这个过程,从而达到控制内存消耗,避免浪费。

不管从设计原理仍是使用方法上看,CoreData都比较复杂。所以,若是仅仅是考虑缓存数据这个需求,CoreData绝对不是一个优选方案。CoreData的使用场景在于:整个应用使用CoreData规划,把应用内的数据经过CoreData建模,彻底基于CoreData架构应用。

苹果官方给出的一个示例代码,结构相对简单,能够帮助你们入门CoreData。

使用基本对象类型定制的个性化缓存方案

以前提到的NSUserDefaults和SQLite适合存储基础类型的小数据,而CoreData则不适合存储单一的数据,那么对于相似图片这种较大的数据要用什么方式储存呢?我给出的建议就是:本身实现一套存储方案。说到订制存储方案你们很是容易质疑,这是否是又在从新发明轮子。我能够很是明确的告诉你们,这毫不是在从新发明轮子。首先要明确,这个所谓的定制方案适用于互联网应用中对远程数据的缓存,几个限制条件缺一不可。

从需求出发分析缓存数据有哪些要求:按Key查找,快速读取,写入不影响正常操做,不浪费内存,支持归档。这些都是基本需求,那么再进一步或许还须要固定缓存项数量,支持队列缓存,缓存过时等。从这些需求入手设计一个缓存方案并不十分复杂,Kache是笔者根据开发应用的需求开发的一套缓存组件,经过分析Kache但愿能够给你们一个思路。

\

图5,Kache架构图

如上图所示,Kache扮演的是一个典型缓存角色。应用加载远程数据生成应用数据对象的同时,经过Kache把数据缓存起来,再次请求则直接经过Kache获取数据。

缓存对象能够是NSDictionary、NSArray、NSSet或NSData这些可直接归档的类型,每一个缓存对象对应一个Key。缓存对象包括数据和过时时间,内存中存放在一个单例字典中,闪存中每一个对象存为一个文件。Key空间按照各类顺序存放缓存对象的Key集合,Pool为固定大小的数组,当数量达到上限,最先过时的一个Key将被删除,对应的缓存对象也被清除。Queue也是固定大小的数组,以先进先出的规则管理Key的增删。 每一次有新的缓存对象存入,自动检测Key空间中过时的集合并清除。

此外,控件提供save和load方法支持持久化和从新载入。

Kache最初设计为存放图片缓存,以后也曾用于缓存文本数据,因为使用了过时和归档相结合的逻辑,能够保证大部分命中的缓存对象都在内存中,从而获取了较高的效率。读者能够从Github上获取Kache源码了解更多。

以上介绍了几种iOS开发中常常会遇到的储存数据方法,从其存储原理、使用方式和适用场景几方面进行进了简单的对比。事实上每一款应用都很难采用一种单一的方案完成整个应用的数据储存任务,须要根据不一样的数据类型,选择最合适的方案,以便整个应用得到良好的运行时性能。

原文地址:http://www.weste.net/2013/3-29/90016.html