iOS 数据持久化方案大致可以分为四种。  
- 属性列表(plist)  
- 对象归档、解档  
- NSUserDefault
- 数据库  
了解数据持久化首先需要了解一个应用目录(沙盒机制)下的文件目录结构。   
| 12
 3
 4
 5
 
 | - Documents - Library
 - Caches
 - Preferences
 - tmp
 
 | 
| 12
 
 | NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
 
 | 
一些宏定义
| 12
 3
 4
 
 | #define DATABASE_PATH [PATH_OF_DOCUMENT stringByAppendingPathComponent:@"anbao.db"]#define PATH_OF_APP_HOME    NSHomeDirectory()
 #define PATH_OF_TEMP        NSTemporaryDirectory()
 #define PATH_OF_DOCUMENT    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
 
 | 
可以被序列化的类型介绍
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | NSArray;NSMutableArray;
 NSDictionary;
 NSMutableDictionary;
 NSData;
 NSMutableData;
 NSString;
 NSMutableString;
 NSNumber;
 NSDate;
 
 | 
plist文件
plist文件可以将某些特定的类,以XML的格式保存起来,比较常见的plist的文件Info.plist
图片显示的就是plist文件所对应的XML文件格式。  
1.获取文件
在项目的根目录下存在一个demo.plist
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | NSString *path = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"plist"];
 
 if([[NSFileManager defaultManager] fileExistsAtPath:path]) {
 NSLog(@"%@",path);
 
 
 }
 else {
 NSLog(@"文件不存在!");
 }
 
 | 
2.读取文件内容  
| 12
 
 | NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithContentsOfFile:path];NSLog(@"%@", result);
 
 | 
输出  
| 12
 3
 
 | 2016-10-13 21:54:06.831 SaveDemo[986:103991] {demoKey = demoValue;
 }
 
 | 
3.写入文件  
| 12
 3
 4
 
 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
 [dict setObject:@"inputValue" forKey:@"inputKey"];
 [dict writeToFile:path atomically:YES];
 
 | 
归档、解档
归档是iOS序列化的一种方式,我们需要实现的一个协议NSCoding协议  
1.协议说明  
NSCoding协议才是归档和解档的一个重要协议,其中需要实现两个方法:  
| 12
 
 | - (void) encodeWithCoder:(NSCoder *)aCoder;- (id) initWithCoder:(NSCoder *)aDecoder
 
 | 
2.NSKeyedArchiver 和 NSKeyedUnarchiver  
| 12
 
 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userBean];
 
 | 
自定义类的对象是无法直接写入文件或者存入 NSUserDefault 中的,此时就需要对该对象进行归档。之后得到的NSData数据之后就可以进一步的使用 文件的I/O 或者 NSUserDefault 存入本地。
| 12
 
 | UserBean *userBean = [NSKeyedUnarchiver unarchiveObjectWithData:data];
 
 | 
NSUserDefault
应该算是比较常用的轻量级持久化方法,对于存一些当前用户的信息、状态等都是不错的选择。之前提到的沙盒机制,对于 NSUserDefault 的数据存放在 Library/Preferences 文件下。对于 app 的更新 NSUserDefault 的数据是不会删除的,除非用户卸载 app。  
1.存入对象要求  
- 遵循NSCoding协议的对象才能存入NSUserDefault,如:UIImage 例外。
- 对于比较大的数据不建议使用NSUserDefault。(据说NSUserDefault的 I/O 比较慢)  
2.存取   
| 12
 3
 4
 
 | [[NSUserDefaults standardUserDefaults] setObject:@"demoValue" forKey:@"demoKey"];
 
 NSLog(@"%@",[[NSUserDefaults standardUserDefaults] valueForKey:@"demoKey"]);
 
 | 
对于存基本型的几个方法: 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | - (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;- (void)setFloat:(float)value forKey:(NSString *)defaultName;
 - (void)setDouble:(double)value forKey:(NSString *)defaultName;
 - (void)setBool:(BOOL)value forKey:(NSString *)defaultName;
 
 - (NSInteger)integerForKey:(NSString *)defaultName;
 - (float)floatForKey:(NSString *)defaultName;
 - (double)doubleForKey:(NSString *)defaultName;
 - (BOOL)boolForKey:(NSString *)defaultName;
 
 | 
数据库
数据库这里想简单介绍一下 FMDB 第三方库。FMDB 是 iOS 平台的SQLite 数据库框架,它是封装了 SQLite 的 C语言 API。
主要有三个类:  
- FMDatabase (用来执行SQL)
- FMResultSet (查询结果集)
- FMDatabaseQueue (多线程中执行操作,线程安全)  
1.封装成工具类  
FMDBTools.h 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | #import <Foundation/Foundation.h>#import "FMDatabase.h"
 
 @interface FMDBTools : NSObject
 
 @property (strong,nonatomic) FMDatabase *fmdb;
 
 + (instancetype) shareFMDBTools;
 
 
 - (void) fmDatabaseOpen;
 
 
 - (void) fmDatabaseClose;
 
 @end
 
 | 
FMDBTools.m
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | #import "FMDBTools.h"
 
 @implementation FMDBTools
 
 + (instancetype) shareFMDBTools {
 static FMDBTools *shareFMDBTools = nil;
 static dispatch_once_t predicate;
 
 dispatch_once(&predicate, ^{
 shareFMDBTools = [[self alloc] init];
 });
 return shareFMDBTools;
 }
 
 - (FMDatabase *) fmdb {
 if(!_fmdb){
 
 
 NSLog(@"databaseWithPath - %@",DATABASE_PATH);
 _fmdb = [FMDatabase databaseWithPath:DATABASE_PATH];
 }
 return _fmdb;
 }
 
 - (void) fmDatabaseClose{
 [self.fmdb close];
 }
 
 - (void) fmDatabaseOpen{
 [self.fmdb open];
 }
 
 @end
 
 | 
2.建立数据库 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | - (void) createXXXTable{
 NSFileManager * fileManager = [NSFileManager defaultManager];
 if ([fileManager fileExistsAtPath:DATABASE_PATH] == NO) {
 
 
 if ([[FMDBTools shareFMDBTools].fmdb open]) {
 NSString * sql = @"CREATE TABLE 'tb_videostatus' ('id' INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL , 'userId' INTEGER, 'status' INTEGER NOT NULL DEFAULT 0,)";
 BOOL res = [[FMDBTools shareFMDBTools].fmdb executeUpdate:sql];
 if (!res) {
 NSLog(@"error when creating db table");
 } else {
 NSLog(@"succ to creating db table");
 }
 [[FMDBTools shareFMDBTools].fmdb  close];
 } else {
 NSLog(@"error when open db");
 }
 }
 else {
 NSLog(@"数据库已存在!");
 }
 }
 
 | 
3.数据库操作  
插入
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | if ([[FMDBTools shareFMDBTools].fmdb open]) {
 if([self queryVideoStatusTableWithVideoId:videoId CourseId:courseId UserId:userId]){
 [[FMDBTools shareFMDBTools].fmdb close];
 return ;
 }
 
 NSString * sql = SQL插入语句
 BOOL res = [[FMDBTools shareFMDBTools].fmdb executeUpdate:sql];
 if (!res) {
 NSLog(@"error to insert data");
 } else {
 NSLog(@"succ to insert data");
 }
 [[FMDBTools shareFMDBTools].fmdb close];
 }
 
 | 
更新  
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | if ([[FMDBTools shareFMDBTools].fmdb open]) {
 NSString * sql = SQL更新语句;
 
 BOOL res = [[FMDBTools shareFMDBTools].fmdb executeUpdate:sql];
 if (!res) {
 NSLog(@"error to update data");
 } else {
 NSLog(@"succ to update data");
 }
 [[FMDBTools shareFMDBTools].fmdb close];
 }
 
 | 
以上只是一些简单的数据库操作,关于多线程中的操作再之后的涉及到再做总结。  
总结
数据持久化对于 app 来说还是很重要的,设计一个合理的持久化方案可以让 app 体验更佳。总结的不恰当之处,还请见谅。