常用的持久化方式包括以下几种:
1.NSUserDefaults (偏好设置)
2.plist存储(属性列表)
3.NSKeyedArchiver(归档序列化存储)
4.SQLite3(iOS的嵌入式关系数据库)
5.FMDB (对sqlite的封装)
6.Core Data (苹果提供的持久化工具)
一、NSUserDefaults (偏好设置)上篇介绍过就不再介绍
优点:快速效率高,简单易用
缺点:只能存储常用的类型
二、plist存储(属性列表)
优点:快速效率高
缺点:不灵活,只能存储常用的类型
可以使用plist存储的类型如下:NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSData、NSMutableData、NSString、NSMutableString、NSNumber、NSDate
//写入文件
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [doc stringByAppendingPathComponent:@"myself.plist"];
NSDictionary *dict = @{@"name": @"hello"};
[dict writeToFile:path atomically:YES];
//读取文件
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
三、归档(NSCoding NSKeyedArchiver NSKeyedUnarchiver)
优点:可以实现把自定义的对象存放在文件中
缺点:必须实现协议,浸入性强
需要保存的对象必须遵守NSCoding协议,并且实现该协议中- (void)encodeWithCoder:(NSCoder )aCoder和 - (id)initWithCoder:(NSCoder )aDecoder方法。
//写入文件
//YXPerson.h文件如下:
@interface YXPerson : NSObject<NSCoding>
@property(nonatomic,copy) NSString *name;
@property(nonatomic,assign) int age;
@end
//YXPerson.m文件如下:
#import "YYPerson.h"
@implementation YYPerson
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self=[super init]) {
self.name=[aDecoder decodeObjectForKey:@"name"];
self.age=[aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
@end
写入和读取:
//写入对象
YXPerson *p=[[YXPerson alloc]init];
p.name=@"hello";
p.age=27;
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *path=[docPath stringByAppendingPathComponent:@"person.hello"];
[NSKeyedArchiver archiveRootObject:p toFile:path];
//读取对象
YXPerson *p=[NSKeyedUnarchiver unarchiveObjectWithFile:path];
四、SQLite3(iOS的嵌入式关系数据库)
优点:灵活、存储大批量的数据
缺点:使用复杂、性能需要自行优化
- (void)openDB{
//获取数据库文件路径
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [doc stringByAppendingPathComponent:@"students.sqlite"];
//将OC字符串转换为c语言的字符串
const char *cfileName = fileName.UTF8String;
//打开数据库文件(如果数据库文件不存在,那么该函数会自动创建数据库文件)
int result = sqlite3_open(cfileName, &_db);
if (result == SQLITE_OK) {//打开成功
NSLog(@"成功打开数据库");
}else{
NSLog(@"打开数据库失败");
}
}
- (void)createTable{
//创建表
const char *sql = "CREATE TABLE IF NOT EXISTS t_student(id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,age integer NOT NULL);";
char *errmsg= NULL;
int result = sqlite3_exec(_db, sql, NULL, NULL, &errmsg);
if (result==SQLITE_OK) {
NSLog(@"创建表成功");
}else{
NSLog(@"创建表失败---%s",errmsg);
}
}
- (void)insertData{
//插入数据
for (int i=0; i<10; i++) {
//拼接sql语句
NSString *name = [NSString stringWithFormat:@"hello--%d",arc4random_uniform(100)];
int age = arc4random_uniform(20)+10;
NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_student (name,age) VALUES ('%@',%d);",name,age];
//执行SQL语句
char *errmsg = NULL;
sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errmsg);
if (errmsg) {//如果有错误信息
NSLog(@"插入数据失败--%s",errmsg);
}else{
NSLog(@"插入数据成功");
}
}
}
- (void)deleteData{
//删除age小于15的数据
NSString *sql = [NSString stringWithFormat:@"DELETE FROM t_student WHERE age<15"];
char *errmsg = NULL;
sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errmsg);
if (errmsg) {
NSLog(@"删除数据失败");
}else{
NSLog(@"删除数据成功");
}
}
- (void)updateData{
//大于20岁的都置为20岁
NSString *sql = [NSString stringWithFormat:@"UPDATE t_student set age=20 WHERE age>20"];
char *errmsg = NULL;
sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errmsg);
if (errmsg) {
NSLog(@"更新数据失败");
}else{
NSLog(@"更新数据成功");
}
}
- (void)queryData{
const char *sql = "SELECT id,name,age FROM t_student WHERE age<20";
sqlite3_stmt *stmt = NULL;
//进行查询前的准备工作
if(sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL)==SQLITE_OK){//SQL语句没有问题
NSLog(@"查询语句没有问题");
//每调用一次sqlite3_step函数,stmt就会指向下一条记录
while (sqlite3_step(stmt)==SQLITE_ROW) {//找到一条记录
//取出数据
//(1)取出第0个字段的值(int)
int ID=sqlite3_column_int(stmt, 0);
//(2)取出第一列字段的值(text)
const unsigned char *name = sqlite3_column_text(stmt, 1);
//(3)取出第二列字段的值(int)
int age = sqlite3_column_int(stmt, 2);
printf("%d %s %d\n",ID,name,age);
}
}else{
NSLog(@"查询语句有问题");
}
}
五、FMDB (对sqlite的封装)
优点:是对sqlite的封装,简单易用,接口比原生的SQLite接口简洁很多,提供一些多线程,缓存,线程池的功能
缺点:因为他是OC的语言封装的,只能在iOS开发中使用
FMDB中重要的类
FMDatabase: 一个FMDatabase对象就代表一个单独的SQLite数据库, 用来执行SQL语句
FMResultSet: 使用FMDatabase执行查询后的结果集
FMDatabaseQueue: 用于在多线程中执行多个查询或更新, 它是线程安全的
**步骤: **
1.下载FMDB文件 , 将FMDB文件添加到工程中
2.导入libsqlite3.0.tbd框架,导入头文件FMDatabase.h
3.代码实现,与SQLite使用步骤相似, 创建数据库路径,获得数据库路径, 打开数据库,然后对数据库进行增删改查,关闭数据库.
初始化数据库:
- (void)createDataBase {
// 获取数据库文件的路径
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [docPath stringByAppendingPathComponent:@"student.sqlite"];
NSLog(@"path = %@",path);
// 1..创建数据库对象
FMDatabase *db = [FMDatabase databaseWithPath:path];
// 2.打开数据库
if ([db open]) {
// do something
NSLog(@"Open database Success");
} else {
NSLog(@"fail to open database");
}
}
FMDB详解,可参考:
iOS-FMDB详解及使用
六、Core Data (苹果提供的持久化工具)
Core Date是ios3.0后引入的数据持久化解决方案,它是是苹果官方推荐使用的,不需要借助第三方框架。Core Date实际上是对SQLite的封装,提供了更高级的持久化方式。在对数据库操作时,不需要使用sql语句,也就意味着即使不懂sql语句,也可以操作数据库中的数据。
优点:相对于SQLite,更加简便
缺点:对批量数据的处理执行效率低
个人感觉Core Data使用体验不太好,虽然简化了sql语句,但是操作维护起来也很复杂。
有兴趣可以参考:
iOS CoreData介绍和使用