存储方式介绍
- NSKeyedArchiver: 采用归档的形式来保存数据沙盒中;
- NSUserDefaults:偏好设置数据存到沙盒的Library/Preferences目录(本质是plist);
- Write写入方式: 永久保存在磁盘中;
- 采用SQLite等数据库来存储数据。
1.NSKeyedArchiver:(归档)
采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。
前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码。
缺点:
归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据。
注: initWithCoder什么时候需要调用[super initWithCoder:]
• initWithCoder原理:只要解析文件就会调用,xib,storyboard都是文件,因此只要解析这两个文件,就会调用initWithCoder。
• 因此如果在storyboard使用自定义view,重写initWithCoder方法,一定要调用[super initWithCoder:],因为只有系统才知道怎么解析storyboard,如果没有调用,就解析不了这个文件。
2.NSUserDefaults:(偏好设置,本质是plist)
用来保存应用程序设置和属性、用户保存的数据。用户再次打开程序或开机后这些数据仍然存在。
NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。
- 好处:1.不需要关心文件名
2.快速做键值对存储 - 坏处: 能及时存储,需要做同步操作,把内存中的数据同步到硬盘上
底层:就是封装了一个字典
- 沙盒结构分析:
- 应用程序包:包含了所有的资源文件和可执行文件。
- Documents:保存应用运行时成成的需要持久化的数据,iTunes同步设备时会备份该目录。(例如,游戏应用可将游戏存到保存在该目录。大型数据不能存放在这里,一旦存放,iOS审核不会通过)
- tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录。
- Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据。(一般把缓存下载好的文件放在这里)
- Library/Preference:保存应用的所有偏好设置,iOS的settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备会备份该目录。
注:在iOS7之前,默认不会马上跟硬盘同步,可以调用[userDefaults synchronize]; 同步操作
3. Write写入方式:永久保存在磁盘中。
4. 采用数据库来存储数据。
4.1 SQLite
SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库。iOS SDK很早就支持了SQLite,在使用时,只需要加入 libsqlite3.dylib 依赖以及引入 sqlite3.h 头文件即可。但是,原生的SQLite API在使用上相当不友好,在使用时,非常不便。
4.2 FMDB
- 什么是FMDB
FMDB是iOS平台的SQLite数据库框架
FMDB以OC的方式封装了SQLite的C语言API - FMDB的优点
使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
对比苹果自带的Core Data框架,更加轻量级和灵活
提供了多线程安全的数据库操作方法,有效地防止数据混乱 - FMDB有三个主要的类
- FMDatabase
一个FMDatabase对象就代表一个单独的SQLite数据库
用来执行SQL语句 - FMResultSet
使用FMDatabase执行查询后的结果集 - FMDatabaseQueue
用于在多线程中执行多个查询或更新,它是线程安全的
通过指定SQLite数据库文件路径来创建FMDatabase对象
//获得数据库文件路径 NSString *doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName=[doc stringByAppendingPathComponent:@"user.sqlite"];
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"数据库打开失败!");
}
执行更新
在FMDB中,除查询以外的所有操作,都称为“更新”
create、drop、insert、update、delete等
使用executeUpdate:方法执行更新
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
//示例
[db executeUpdate:@"UPDATE t_user SET age = ? WHERE name = ?;", @20, @"Jack"]
执行查询
查询方法
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
示例
// 查询数据
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_user"];
// 遍历结果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
NSString *sex = [rs doubleForColumn:@"sex"];
}
使用FMDatabaseQueue
线程安全:在多个线程中同时使用一个FMDatabase实例是不明智的。现在你可以为每个线程创建一个FMDatabase对象。 不要让多个线程分享同一个实例,它无法在多个线程中同时使用。 若此,程序会时不时崩溃,或者报告异常,让人崩溃。所以,不要初始化FMDatabase对象,然后在多个线程中使用。
请使用 FMDatabaseQueue。以下是使用方法:
//首先创建队列。
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
//这样使用。
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
FMResultSet *rs = [db executeQuery:@"select * from foo"];
while([rs next]) { … }}];
//像这样,轻松地把简单任务包装到事务里:
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
if (whoopsSomethingWrongHappened) { *rollback = YES; return; }
// etc… [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; }];
FMDatabaseQueue 后台会建立系列化的G-C-D队列,并执行你传给G-C-D队列的块。这意味着 你从多线程同时调用调用方法,GDC也会按它接收的块的顺序来执行。
4.3 Realm
在移动领域,SQLite数据库一直占据着不可撼动的地位。SQLite的缔造者遵循小而精的理念,使用极少量的C代码实现了关系型数据库的核心逻辑。然而,当关系型数据库遇到了面向对象编程语言时,一个困扰着程序员们的难题出现了。为了实现关系型数据到对象的转换,我们需要使用SQL语句查询到相应的值。然后,再给对象赋值。这些重复的工作给编码带来了一些麻烦,为了解决这个难题,ORM框架出现了
ORM (Object Relational Mapping)
ORM框架避免了你直接使用SQL语句进行查询。而是直接使用面向对象的方式帮助你完成数据的查询,并且自动映射到相应的对象中。这对于一些受够了繁琐SQL语句编写的程序员来说,简直就是救星。
其实,Realm依然是关系型数据库的ORM解决方案,比较不可思议的是:Realm在增删改查操作中速度几乎都优于SQLite,或者接近SQLite。同样是ORM框架,为什么Realm可以拥有如此惊人的速度呢?
答案是:Realm的底层实现基本采用C++, 原生支持面向对象查询。同时进行了大量的优化,才终于拥有了和SQLite一样的性能。
性能方面的担忧不用考虑了,便开始查看官方文档,Realm的官方文档也非常详细,甚至还有中文版本。
对于移动端数据库,下面几个方面是不得不考虑的:
1)数据库版本的升级
2)是否完善的外部调试工具
3)复杂查询是否支持
Realm官方文档上面,有对这三个问题的详细解答,下面我来简单阐述一下:
第一个问题,Realm提供了Migration类实现对Realm数据库版本的升级维护。
第二个问题,Realm提供了Realm Browser的mac版本,方便在Mac机器上面进行调试。不过,遗憾的是,相关工具并没有提供Windows版本,lol 。
第三个问题,Realm有相关章节,专门介绍了多表查询方法,以及一对多,多对多数据表解决方案。
4.4 CoreData
什么是CoreData?
- Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象。在此数据操作期间,我们不需要编写任何SQL语句
- CoreData 不能执行SQL语句 取而代之,操作的是对象。而常用的三方库 FMDB SQLite 可以直接SQL语句
CoreData和数据库有什么区别?
CoreData是一个苹果原生的框架,它拥有像数据库一样存储数据的功能,但本身并不是数据库
- Core Data 是iOS SDK 里的一个很强大的框架,允许程序员以面向对象的方式储存和管 理数据。使用Core Data 框架,程序员可以很轻松有效地通过面向对象的接口管理数据,所以说CoreData不是数据库,不要以数据库的眼光看待.
Core Data 不是应用程序的数据库,也不是将数据持久化保存到数据库的API。Core Data 是一个 用于管理对象图的框架。Core Data 可以把对象图写入磁盘从而持久化保存
CoreData有什么特点?
(1)CoreData提供了模型层的技术,可以直接对OC对象进行数据持久化
- Core Data 是一个模型层的技术。帮助建立代表程序状态的模型层,Core Data 也是一种 持久化技术,能将模型对象的状态持久化到磁盘,但它最重要的特点是:Core Data 不仅是 一个加载、保存数据的框架,它还能和内存中的数据很好的共事
- (2)在数据的存储操作过程中,CoreData无需编写任何SQL语句
- (3)Core Data 使用包括实体和实体间关系,以及查找符合某些条件实体的请求等内容
- (4)开发者可以在纯对象层上查找与管理这些数据,而不必担心存储和查找的实现细节
- (5)Core Data 框架最早出现在Mac OS X 10.4 Tiger 与iOS 3.0 系统,经过成千上万的应 用程序以及数以百万用户的反复的验证,Core Data 确实已经是一套非常成熟的框架
- (6)CoreData 利用了Objective-C 语言和运行时,巧妙地集成了Core Foundation 框架。是 一个易于使用的框架,不仅可以优雅地管理对象图,而且在内存管理方面表现异常优异
CoreData原理:
- 第一眼看到Core Data 令人生畏的复杂架构关系,很多人都会有无从下手的感觉
- 可是,一旦理解了架构图中各个部件的组成及相互之间的关系,就能体会到Core Data API 的简 洁和直观了
Core Data stack(技术堆栈):如果能够理解Core Data stack 中的各个成员所扮演的角色,那么再 使用Core Data 就不会感觉到困难了
1.1-什么是CoreData Stack?
Core Data stack 是Core Data 的核心,由一组Core Data 核心对象组成
- NSManagedObjectContext 对象管理上下文: 负责管理模型的对象的集合
- NSManagedObjectModel 被管理的对象模型: 负责管理对象模型
- NSPersistentStoreCoordinator 存储调度器: 负责将数据保存到磁盘的
1.2-CoreData Stack中的对象是如何协调工作的呢?
组成可分为两部分
- 对象图管理:主要是指对象管理上下文(NSManagedObjectContext)通过对对象模型(NSManagedObjectModel)实施对象管理.
数据持久化:主要是指存储器(NSPersistentStore)来操作SQLite数据库,将数据存储在磁盘中(这部分是系统帮我们完成不需要我们管).
- 在这两部分的中间,即堆栈中间,是持久化存储协调器(Persistent Store Coordinator, PSC)。通过它将对 象图管理部分和持久化部分绑在一起。当这两部分中的一部分需要和另一部分交互,将通过PSC 来 调节
- 其中的注意点:
- 一个工程可以有多个管理模型的Context,一个存储调度器可以调度多个存储器,不过在一般的开发中,我们只需要一个Contect和一个存储器就足够了