数据持久化方案(若是总结不到位,或者有误的地方,敬请斧正)sql
1、功能:数据库
主要是将数据持久化到本地,减小对网络请求的次数,既节省了用户的流量,也加强了App的体验效果。数组
2、种类:缓存
plist存储:使用XML键值对持久化,它适用于少许且数据基本不怎么改变的状况。安全
偏好存储:使用NSUserDefalut持久化,专门用来保存应用程序的配置信息的,通常不要在偏好设置中保存其余数据。网络
归档序列化存储:使用二进制序列化持久化,只要遵循了NSCoding协议的对象均可以经过它实现序列化。多线程
沙盒存储:持久化在Document目录下,通常持久化一些文件,好比图片,音频,视频等,文件沙盒存储主要存储非机密数据。app
本地数据库存储:适合储存大规模数据,管理方便,不过操做稍微复杂一些。框架
3、详解:函数
一、plist存储
定义:
plist文件,即属性列表文件,全名是Property List,这种文件的扩展名为.plist,所以,一般被叫作plist文件。
做用:
它是一种用来存储串行化后的对象的文件,在iOS开发中一般用来存储用户设置,还能够用于存储程序中常常用到而不常常改动的数据。
问题:
(1)什么数据适合存储?
能存储NSString、NSArray、NSDictionary、NSData、NSDate、NSNumber、Boolean不能存储自定义对象
(2)存到什么地方?
写入建立的.plist文件中
(3)使用场景?
plist经常使用于存储长时间不容易发生变化的数据,例如省市列表、车辆名称列表之类的数据等,这些数据能够保存在 plist 文件里,因此plist适用于存储小型数据,不推荐用plist作缓冲。
(4)如何使用?
存储
[dict writeToFile:filePath atomically:YES]; // 字典 [array writeToFile:filePath atomically:YES]; // 数组 [string writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; // 字符串
获取
NSArray *arr = [NSArray arrayWithContentsOfFile:filePath]; // 数组 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath]; // 字典 NSString *string = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; // 字符串
(5)有什么缺点?
由于全部的数据都放在root dictionary里,每次读取都要把整个root dictionary取出来再取须要的对象.若是plist文件缓存了几十M的数据.这样很费内存和时间。
二、偏好存储
定义:
User Defaults 顾名思义就是一个用户为系统以及程序设置的默认值。
每一个用户都有本身的一套数据,用户和用户之间无法共享的。在苹果的API中,提供了一个类去存储用户的偏好设置。
这个方法推荐只存储用户的偏好设置,不要存储一些字典、数组之类的。
做用:
不少iOS应用都支持偏好设置,好比保存用户名、密码、字体大小等设置。
iOS提供了一套标准的解决方案来为应用加入偏好设置功能,就是每个app都有一个plist文件专门用以保存偏好设置数据。
每一个应用都有个NSUserDefaults实例,经过它来存取偏好设置。
问题:
(1)什么数据适合存储?
能够存储OC定义的全部数据类型,包括对象(系统和自定义的)类型、基本数据类型,如NSInteger等。
(2)存到什么地方?
NSUserDefault 本地保存的位置是Library/Preferences 这个目录下的 plist 文件。
(3)使用场景?
在App中,有时候咱们须要将一些信息进行短时间的保存,方便用户下次更方便使用App,减小多余的操做,加强用户体验。
好比,保存用户名、字体大小、是否自动登陆等。
(4)如何使用?
存储
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; [defaults setObject: forKey:];
[defaults setInteger:forKey:];
[defaults setDouble: forKey:];
[defaults setObject: forKey:];
[defaults synchronize];
获取
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults objectForKey:];
[defaults objectForKey:];
[defaults integerForKey:];
[defaults doubleForKey:];
(5)注意事项?
三、归档序列化存储
定义:
对象归档是iOS中数据持久化的一种方式。 归档是指另外一种形式的二进制序列化,但它是任何对象均可以实现的更常规的类型。
做用:
使用对模型对象进行归档的技术能够轻松将复杂的对象写入文件,而后再从中读取它们。
问题:
(1)什么数据适合存储?
要使用对象归档,则归档的对象所属类中实现的每一个属性都是标量,或者都是遵循NSCoding协议和NSCopying协议的某个类的实例对象。
(2)存到什么地方?
对象归档后将获得一个后缀为.archive的文件,数据就保存在了这个文件中。
(3)使用场景?
定义某个实例,若是须要持久化该实例从而方便之后使用它的属性值,同时能够随意更改该实例的属性值,推荐在给实例初始化的同时直接使用归档进行存储。
(4)如何使用?
遵循NSCoding协议
实现NSCopying协议
存储
NSMutableData *data = [[NSMutableData alloc] init]; //声明一个二进制流 data,开辟了一个空间 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //声明一个归档类,把归档类的内容放入data中
[archiver encodeObject:id forKey:Key]; //用Key进行编码 [archiver finishEncoding]; //结束编码 [data writeToFile:filePath atomically:YES];//编码结束后,归档类的内容已经放入data中了,此时data仍然驻留在内存中,须要写入文件中
获取
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:filePath];//用归档文件中的数据初始化 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];//声明一个解归档对象,把data中的数据复制给解归档对象 id object = [unarchiver decodeObjectForKey:Key]; //用Key进行解码 [unarchiver finishDecoding]; //结束解码
(5)有什么缺点?
当待存储的实例具备成百上千个属性的时候,单纯的一个个去序列化属性值耗时又费力。(固然能够借助runtime机制解决这个缺点,MJExtension这个框架就是这个原理)
四、Document沙盒存储
定义:
每一个iOS应用都有本身的应用沙盒(应用沙盒就是文件系统目录),与其余文件系统隔离。
应用必须待在本身的沙盒里,其余应用不能访问该沙盒。
沙盒的本质就是一个文件夹,名字是随机分配的。
目录:
// 获取程序的Home目录 NSString *path = NSHomeDirectory(); // 获取Document目录 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) fristObject]; // 获取Cache目录 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) fristObject]; // 获取Library目录 NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) fristObject]; // 获取Tmp目录 NSString *path = NSTemporaryDirectory();
做用:
用来存储和备份稍微较大的不是很重要的数据,好比缓存图片、音频、视频等,最典型的SDWebImage缓存图片的框架。
固然缓存的时间长短根据开发者选择持久化的目录路径有关。
问题:
(1)什么数据适合存储?
图片、音频、视频、文本等
(2)存到什么地方?
写入建立的.txt、.data等任意扩展名的文件中
(3)使用场景?
当App中涉及到电子书阅读、听音乐、看视频、刷图片列表等时,推荐使用沙盒存储。
由于这能够极大的节约用户流量,并且也加强了app的体验效果。
(4)如何使用?
写入文件
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) fristObject]; NSArray *array = [[NSArray alloc] initWithObjects:@"内容",@"content",nil]; NSString *filePath = [path stringByAppendingPathComponent:@"testFile.txt"]; [array writeToFile:filePath atomically:YES];
读取文件
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) fristObject]; NSString *filePath = [path stringByAppendingPathComponent:@"testFile.txt"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
五、本地数据库存储
定义:
数据库是一种经常使用的经过表进行数据存储的方式,表与表之间能够有一对1、一对多的联系,使用外键级联能够达到多表存取数据的目的。
在iOS中,目前有三种熟知数据库,分别是Sqlite、CoreData、FMDB,用的比较多的是FMDB+Sqlite结合的方式。
特色:
Sqlite:
CoreData;
FMDB;
做用:
用来进行大数据量的存储工做,不只仅是容量大,并且经过索引查找速度很快,在App中这个是基本的功能。
问题:
(1)什么数据适合存储?
开发者定义的类的实例对象,该对象拥有的属性能够是任何类型,例如数字、 字符、 日期、 图片等等。
(2)存到什么地方?
写入建立的.sqlite、.db等任意扩展名的文件中
(3)使用场景?
在App中有大量的数据在没有网络的状况下仍然须要显示时,此时推荐使用本地数据库缓存这些数据。
(4)如何使用?
Sqlite:
源码
NSString *sqlStr = @"INSERT OR REPLACE INTO note (cdate,content) VALUES (?,?)"; sqlite3_stmt *statement; //预处理过程,产生结果集 if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *nsdate = [dateFormatter stringFromDate:model.date]; //绑定参数开始 sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL); sqlite3_bind_text(statement, 2, [model.content UTF8String], -1, NULL); //执行插入 if (sqlite3_step(statement) != SQLITE_DONE) { NSAssert(NO, @"插入数据失败。"); } } } //清理结果集,防止内存泄露 sqlite3_finalize(statement);
CoreData;
源码
//获取实体对象 NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@“ClassName” inManagedObjectContext:self.managedObjectContext]; //建立请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“ClassName”]; //建立排序对象 NSSortDescriptor *ageSort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES] [request setSortDescriptors:@[ageSort]]; //取出全部的数据 NSArray *fetcheObjects = [self.managedObjectContext executeFetchRequest:request error:&error]
FMDB:
self.db = [FMDatabase databaseWithPath:fileName]; //建立数据库
[self.db open];//打开数据库
- (FMResultSet *)executeQuery:(NSString*)sql, ... //返回结果集
- (BOOL)next; //遍历
- { type }ForColumnIndex:(int)columnIdx //取出某一行对应的具体数据
- (BOOL)executeUpdate:(NSString*)sql, ... //执行更新
[self.db close]; //关闭数据库
源码
//<1>使用:(须要FMDatabase *db成员变量) //建立或打开:FMDataBase类 self.db = [FMDatabase databaseWithPath:fileName]; [self.db open]; [self.db executeUpdate:@“CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT,age INTEGER)”]; [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(‘admin’,‘10')]; //<2>查询:FMResultSet类 //1.查询 FMResultSet *set = [self.db executeQuery:@"SELECT * FROM t_student;"]; //2.取出数据 即 {type}ForColumnIndex: while ([set next]) { //取出姓名 NSString *name = [set stringForColumnIndex:1]; //取出年龄 int age = [set intForColumnIndex:2]; NSString *name = [set stringForColumn:@"name"]; int age = [set intForColumn:@"age"]; NSLog(@"name = %@, age = %d", name, age); } //<3>关闭数据库 [self.db close];
既然有这五种存储方案,那么在项目中应该选择哪一种是最佳的方式呢,这就涉及到了下面这个问题了。
针对上面的这个问题,基本是能够有四种参考的维度,分别是:
如今就具体的列表说一下这些区别。
存储方式
|
数据量
|
数据类型
|
数据载体
|
数据操做特色
|
应用示例
|
---|---|---|---|---|---|
plist存储 | 适合存储小数据量并且属于一类的列表类的数据 | 只能存储固定的几种类型,NSString、NSArray、NSDictionary、NSData、NSDate、NSNumber、Boolean,不能存储自定义对象 | 非自定义实例对象、基本数据 | 直接在可见文件上操做,增删改查很方便 |
省市列表、表情列表等 |
偏好存储 | 适合存储小数据量而是通常是配置信息类的数据,有时根据须要也会存储一些标志键值数据 | 能够存储OC定义的全部数据类型 |
实例对象、基本数据 |
必须依赖NSUserDefaluts实例对象的实例方法进行存取,过程稍微复杂 |
App应用程序的信息配置,如版本号、app名称、用户权限等 标志键值,如判断启动页、是否自动登陆等 |
归档存储 | 适合存储数据量稍微较大的数据 | 只能存储实现了NSCoding协议和NSCopying协议的实例对象类型。 | 实例对象 | 必须依赖NSKeyedUnarchiver、NSKeyedArchiver的类方法或者实例方法进行存取,有时可能还会结合NSUserDefaluts偏好,过程比较复杂 | 用户的登陆/注册信息,如帐号、姓名、年龄、学校、省份等 |
沙盒存储 | 适合存储数据量较大的数据 | 都是存储二进制的NSdata类型 | 文件File | 须要依赖文件管理者NSFileManager将文件写入指定的沙盒目录下、从该目录中再读取文件,过程更复杂一些 | 图片、音频、视频、文本等,如SDWebImage图片缓存框架 |
数据库存储 | 适合存储大数据量的数据 | 支持全部的数据类型 | 实例对象 | 增删改查方便、快捷,能够任意写sql语句批量处理数据、数据库升级简单等 | App中用户浏览过的数据列表内容、电子书读书进度等,基本上大多数app都有本地数据库缓存 |