谈到数据储存,首先要明确区分两个概念,数据结构和储存方式。所谓数据结构就是数据存在的形式。除了基本的NSDictionary、NSArray和NSSet这些对象,还有更复杂的如:关系模型、对象图和属性列表多种结构。而存储方式则简单的分为两种:内存与闪存。内存存储是临时的,运行时有效的,但效率高,而闪存则是一种持久化存储,但产生I/O消耗,效率相对低。把内存数据转移到闪存中进行持久化的操作称成为归档。
二者结合起来才是完整的数据存储方案,我们最常谈起的那些:SQLite、CoreData、NSUserDefaults等都是数据存储方案。当然在这些框架提供的方案之外,我们自己也可以按照个性化需求订制方案。这些存储方案侧重不同,支持的形式和方式也各不相同,在不同的使用场景下表现也是各有优劣。但万变不离其宗,无论什么方案都可以用下图来解释。
在IOS中基本的几种数据存储机制有:
- 对象归档(固化)
- 属性类表
- SQLite
- Core Data
- NSUserDefault 用户配置信息
- 基本的缓存机制
对象归档由IOS SDK 提供的一种保存和读取对象的机制,使用非常广泛。当应用归档某个对象时,会将该对象的所有实例变量存入到指定的文件。当应用解归档某个对象的时候,会将其从指定的文件读取出相应的数据,然后根据数据还原对象。为了能够归档或者解归档某个对象,相应的对象的类必须遵守NSCoding协议,并且实现两个必须的方法:
@protocol NSCoding
- (void) encodeWithCoder:(NSCoder *) aCoder;
-(id) initWithCoder:(NSCoder *)aDecoder;
@end
归档指定的文件中,首先要获得文件路径,这里提到一个概念是应用沙盒(application sandbox),每个应用都有自己专属的应用沙盒,应用沙盒就是文件系统中的目录,但是IOS系统会将每个应用的沙盒目录与文件系统的其他部分隔离。通过下面的方法获取文件路径:
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString * documentDirectory = [documentDirectories objectAtIndex:0];
则documentDirectory 就是当前应用的沙盒,但为什么前面documentDirectories 是一个数组呢,因为对Mac OS X,可能会有多个目录匹配某组指定的查询条件,但在IOS上,一个目录类型只会有一个匹配的目录。最终通过归档和解归档函数实现对象的操作:
-(BOOL)NSKeyedArchiver archiveRootObject:(NSDic) items toFile:(NSString *)path;
-(BOOL)NSKeyedUnarchiver unarchiveObjectWithFile:(NSString *)path;
属性类表
Property List这一类型的文件,通常用来存放简单的结构数据,如应用程序的设置。Property List是一个XML格式的文件。如果你之前在Mac或iPhone编辑过配置文件,可能看到过.plist
后缀的文件,它们就是Property List的应用。Property List中存放的数据类型是有限制的,包括数组(Array)、字典(Dictionary)、字符串(String)等。
创建Property List:在模拟器中点击Xcode-New File-Resource-Property List 创建Property List文件。在左侧工程导航栏中点击该文件,即可在模拟器右侧编辑该文件:AddRow添加新值,
所有值均为Key-Value对。如果需要查看plist文件的数据结构,可以右击XXX.plist文件,并选择Open as Source Code来查看Property List所存放的内容。
读取Property List:ios SDK提供了从plist读取数据的方法,可对该文件直接进行读写操作。
代码如下:
NSString *path = [[NSBundle mainBundle] pathForResource:@"recipes" ofType:@"plist"]; // Find out the path of recipes.plist
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path]; // Load the file content and read the data into arrays
tableData = [dict objectForKey:@"RecipeName"];
thumbnails = [dict objectForKey:@"Thumbnail"];
prepTime = [dict objectForKey:@"PrepTime"];
SQLite
SQLite 是一个用C语言编写的开源库,他实现了一个自包含的SQL关系型数据库引擎。可以使用SQLite存储大量的关联数据。SQLite的开发人员已经对其在如iPhone和iPad这样的嵌入式设备上的使用进行了优化。
尽管Core Data应用程序编程接口(API)也被设计用来在IOS上存储数据,但其主要目的是持久化应用程序创建的对象。当预先加载具有大量数据的应用程序时,SQLite的表现比较突出,而Core Data擅长管理在设备上创建的数据。
Core Data
Core Data 是一个API集合,被设计用来简化数据对象的持久存储。Core Data 提供了一个框架用于保存模型对象并在之后取回他们。Core data 还管理对对象模型的改变,提供撤销支持,并确保模型对象之间关系的一致性。所有这些特性使你可以免于编写实现这些功能的代码。本质上,Core data 简化了模型-视图-控制器(MVC)架构中的模型部分的创建。
除了其易用性,Core data 还提供了一些重要的性能改进。Core data 可以使用SQLite 作为其后台数据库。这为Core data 提供了一个高性能的查询引擎。对比通过平面数据文件或着plist进行搜索和排序,Core Data提供更高的速度。另外,通过在任何特定的时间只读取需要的数据,Core Data API 可以节省内存。例如,如果有两个相关的实体,那么在请求其中的子实体前Core Data不会获取它。这样节省了内存,在移动设备上内存这么宝贵的资源。
Core Data 的关键组件时数据存储(data store),持久存储协调器(Persistent Store Coordinator),托管对象模型(Managed Object Model)和托管对象上下文(Managed Object Context),上述四种组件之间的关系如下:
SQLite 和Core Data 的选择
当开始编写以数据为中心的IOS应用程序的时候,需要对架构做出重要决定,即应该使用SQLite还是Core Data 来满足数据管理的需求?
首先,Core Data 不是一个关系型数据库的实现,尽管Core Data 在后台使用SQLite存储数据,但它不是以开发人员可以直接访问的方式存储数据的。实际上,不要尝试人工修改后台数据库结构或者数据。应该只有Core Data 框架能够操作数据库结构和数据。
然后,如果需要关系型数据库提供的功能,无比考虑直接使用SQLite,如果只需要持久化应用程序使用期间创建的对象,则应该考虑使用Core Data。
如果你想要预加载设备上的大量数据,可能会考虑使用SQLite数据库。
简单总结这么多,后续再完善。。。