iOS 数据持久化方案大致可以分为四种。
- 属性列表(plist)
- 对象归档、解档
- NSUserDefault
- 数据库
了解数据持久化首先需要了解一个应用目录(沙盒机制)下的文件目录结构。
1 2 3 4 5
| - Documents - Library - Caches - Preferences - tmp
|
1 2
| NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
|
一些宏定义
1 2 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]
|
可以被序列化的类型介绍
1 2 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
1 2 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.读取文件内容
1 2
| NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; NSLog(@"%@", result);
|
输出
1 2 3
| 2016-10-13 21:54:06.831 SaveDemo[986:103991] { demoKey = demoValue; }
|
3.写入文件
1 2 3 4
| NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; [dict setObject:@"inputValue" forKey:@"inputKey"]; [dict writeToFile:path atomically:YES];
|
归档、解档
归档是iOS序列化的一种方式,我们需要实现的一个协议NSCoding协议
1.协议说明
NSCoding协议才是归档和解档的一个重要协议,其中需要实现两个方法:
1 2
| - (void) encodeWithCoder:(NSCoder *)aCoder; - (id) initWithCoder:(NSCoder *)aDecoder
|
2.NSKeyedArchiver 和 NSKeyedUnarchiver
1 2
| NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userBean];
|
自定义类的对象是无法直接写入文件或者存入 NSUserDefault 中的,此时就需要对该对象进行归档。之后得到的NSData数据之后就可以进一步的使用 文件的I/O 或者 NSUserDefault 存入本地。
1 2
| UserBean *userBean = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
NSUserDefault
应该算是比较常用的轻量级持久化方法,对于存一些当前用户的信息、状态等都是不错的选择。之前提到的沙盒机制,对于 NSUserDefault 的数据存放在 Library/Preferences 文件下。对于 app 的更新 NSUserDefault 的数据是不会删除的,除非用户卸载 app。
1.存入对象要求
- 遵循NSCoding协议的对象才能存入NSUserDefault,如:UIImage 例外。
- 对于比较大的数据不建议使用NSUserDefault。(据说NSUserDefault的 I/O 比较慢)
2.存取
1 2 3 4
| [[NSUserDefaults standardUserDefaults] setObject:@"demoValue" forKey:@"demoKey"];
NSLog(@"%@",[[NSUserDefaults standardUserDefaults] valueForKey:@"demoKey"]);
|
对于存基本型的几个方法:
1 2 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
1 2 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
1 2 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.建立数据库
1 2 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.数据库操作
插入
1 2 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]; }
|
更新
1 2 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 体验更佳。总结的不恰当之处,还请见谅。