您的位置:首页 > 移动开发 > IOS开发

IOS之持久化数据的常用5种方法

2013-10-08 21:30 239 查看
1.用户默认配置.直接写入到系统配置里

NSSt�密的保存数据方式,也是以键值对形式保存读取的.)

例: 所有归档对象必须支持NSCoding协议 和 NSCopying(支持对象复制)

//写入归档文件

NSArray *list = @[[NSArray allc] initWithObjects:@"one", @"two", nil];

NSMutableData *data = [[NSMutableData alloc] init];

NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

[archiver encodeObject:list forKey:@"keyValue"];

[archiver finishEncoding];

BOOL success = [data writeToFile:@"/path/to/archive" atomically:YES];

//成功返回YES

//读取归档文件

NSArray *list = nil;

NSData *data = [[NSData alloc] initWithContentsOfFile:@"/path/t5��密的保存数据方式,也是以键值对形式保存读取的.)

例: 所有归档对象必须支持NSCoding协议 和 NSCopying(支持对象复制)

//写入归档文件

NSArray *list = @[[NSArray allc] initWithObjects:@"one", @"two", nil];

NSMutableData *data = [[NSMutableData alloc] init];

NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

[archiver encodeObject:list forKey:@"keyValue"];

[archiver finishEncoding];

BOOL success = [data writeToFile:@"/path/to/archive" atomically:YES];

//成功返回YES

//读取归档文件

NSArray *list = nil;

NSData *data = [[NSData alloc] initWithContentsOfFile:@"/path/to/archive"];

NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

list = [unarchiver decodeObjectForKey:@"keyValue"];

[unarchiver finishDecoding];

//至此已经完成

4.SQLite3 这是一个小型的数据库 (支持复杂的数据查询和存储)

使用前得引入动态库 libsqlite3.dylib, 使用过程中的字符串类型必须是标准C字符串.

sqlite3_open() //用来打开数据库

sqlite3_prepare_v2() //操作数据库前的准备

sqlite3_step() //分步查询或者执行

sqlite3_column() //查询过后获取列值

sqlite3_bind_*() //当你想要插入或者更新数据时来绑定的内容

sqlite3——reset() //重置这个语句,回到重新绑定的状态

sqlite3_finalize() //销毁这个对象

sqlite3_close() //关闭数据库

 sqlite3_exec是sqlite3_prepare_v2,sqlite3_step()和sqlite3_finalize()的封装,能让程序多次执行sql语句而不要写许多重复的代码。
 Sqlite3_exec接口执行0或多个UTF-8编码的,分号分割的sql语句,传到第二个参数中。如果sqlite3_exec的第三个参数回调函数指针不为空,那么它会为每个来自执行的SQL语句的结果行调用(也就是说回调函数会调用多次,上面例子中会返回2个结果行,因而会被执行2次),第4个参数是传给回调函数的第一个参数,如果回调函数指针为空,那么回调不会发生同时结果行被忽略。

如果在执行sql语句中有错误发生,那么当前的语句的执行被停止,后续的语句也被跳过。第五个参数不为空的时候,它被分配内存并写入了错误信息,所以在sqlite3_exec后面需要调用sqlite3_free去释放这个对象以防止内存泄露
 回调函数:
int (*callback)(void*,int,char**,char**),
/* Callback function */
第一个参数通过sqlite3_exec的第第四个参数传入的
第二个参数是结果行的列数
第三个参数是行中列数据的指针
第四个参数是行中列名称的指针


查询数据

int sqlite3_get_table(sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg );

第1个参数是前面open函数得到的指针。

第2个参数const char *sql 是一条 sql 语句,以\0结尾。

第3个参数是查询结果,它是一维数组 ,它内存布局是:第一行是字段名称,后面是紧接着是每个字段的值。

第4个参数是查询出多少条记录(即查出多少行)。

第5个参数是多少个字段(多少列)。

第6个参数是错误信息。

操作二进制

sqlite3_stmt * 所表示的内容看成是 sql语句,但是实际上它不是我们所熟知的sql语句。它是一个已经把sql语句解析了的、用sqlite自己标记记录的内部数据结构。要插入二进制,前提是这个表的字段的类型是 blob 类型。

假设有一张表:

create table Tbl_2( ID integer, file_content blob )

首先声明

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

// sqlite3_prepare 接口把一条SQL语句编译成字节码留给后面的执行函数. 使用该接口访问数据库是当前比较好的的一种方法.

sqlite3_prepare( db, “insert into Tbl_2( ID, file_content) values( 10, ? )”, -1, &stat, 0 );

上面的函数完成 sql 语句的解析

第一个参数跟前面一样,是个 sqlite3 * 类型变量,

第二个参数是一个 sql 语句。这个 sql 语句特别之处在于 values 里面有个 ? 号。在sqlite3_prepare函数里,?号表示一个未定的值,它的值等下才插入。

第三个参数我写的是-1,这个参数含义是前面 sql 语句的长度。如果小于0,sqlite会自动计算它的长度(把sql语句当成以\0结尾的字符串)。

第四个参数是 sqlite3_stmt 的指针的指针。解析以后的sql语句就放在这个结构里。

第五个参数为0就可以了。

如果这个函数执行成功(返回值是 SQLITE_OK 且 stat 不为NULL ),那么下面就可以开始插入二进制数据。

sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL );

// pdata为数据缓冲区,length_of_data_in_bytes为数据大小,以字节为单位

这个函数一共有5个参数。

第1个参数:是前面prepare得到的 sqlite3_stmt * 类型变量。

第 2个参数:?号的索引。前面prepare的sql语句里有一个?号,假如有多个?号怎么插入?方法就是改变 bind_blob 函数第2个参数。参数为1,表示这里插入的值要替换 stat 的第一个?号(这里的索引从1开始计数,而非从0开始)。如果你有多个?号,就写多个 bind_blob 语句,并改变它们的第2个参数就替换到不同的?号。如果有?号没有替换,sqlite为它取值null。

第3个参数:二进制数据起始指针。

第4个参数:二进制数据的长度,以字节为单位。

第5个参数:是个析构回调函数,告诉sqlite当把数据处理完后调用此函数来析够你的数据。但是一般都填NULL,需要释放的内存自己用代码来释放。

bind完了之后,二进制数据就进入了你的“sql语句”里了。你现在可以把它保存到数据库里:

虚 拟机执行字节码,执行过程是一个步进(stepwise)的过程,每一步(step)由sqlite3_step()启动,并由VDBE(sqlite虚 拟机)执行一段字节 码。由sqlite3_prepare编译字节代码,并由sqlite3_step()启动虚拟机执行。在遍历结果集的过程中,它返回 SQLITE_ROW,当到达结果末尾时,返回SQLITE_DONE

int result = sqlite3_step( stat );

通过这个语句,stat 表示的sql语句就被写到了数据库里。

最后,要把 sqlite3_stmt 结构给释放:sqlite3_finalize( stat ); //把刚才分配的内容析构掉

读出二进制

先声明 sqlite3_stmt * 类型变量:

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

sqlite3_prepare( db, “select * from Tbl_2”, -1, &stat, 0 );

当 prepare 成功之后(返回值是 SQLITE_OK ),开始查询数据。

int result = sqlite3_step( stat );

这一句的返回值是 SQLITE_ROW 时表示成功(不是 SQLITE_OK )。

你可以循环执行 sqlite3_step 函数,一次 step 查询出一条记录。直到返回值不为 SQLITE_ROW 时表示查询结束。

然后开始获取第一个字段:ID 的值。ID是个整数,用下面这个语句获取它的值:

int id = sqlite3_column_int( stat, 0 ); //第2个参数表示获取第几个字段内容,从0开始计算。

下面开始获取 file_content 的值,因为 file_content 是二进制,因此我需要得到它的指针,还有它的长度:

const void * pFileContent = sqlite3_column_blob( stat, 1 );

int len = sqlite3_column_bytes( stat, 1 );

这样就得到了二进制的值。

把 pFileContent 的内容保存出来之后,

不要忘了释放 sqlite3_stmt 结构:

sqlite3_finalize( stat ); //把刚才分配的内容析构掉

重复使用 sqlite3_stmt 结构

如果你需要重复使用 sqlite3_prepare 解析好的 sqlite3_stmt 结构,需要用函数: sqlite3_reset。

result = sqlite3_reset(stat);

这样, stat 结构又成为 sqlite3_prepare 完成时的状态,你可以重新为它 bind 内容。

事务处理

sqlite 是支持事务处理的。如果你知道你要同步删除很多数据,不仿把它们做成一个统一的事务。通常一次 sqlite3_exec 就是一次事务,如果你要删除1万条数据,sqlite就做了1万次:开始新事务->删除一条数据->提交事务->开始新事务 ->… 的过程。这个操作是很慢的。因为时间都花在了开始事务、提交事务上。你可以把这些同类操作做成一个事务,这样如果操作错误,还能够回滚事务。

事务的操作没有特别的接口函数,它就是一个普通的 sql 语句而已:

分别如下:

int result;

result = sqlite3_exec( db, "begin transaction", 0, 0, &zErrorMsg ); //开始一个事务

result = sqlite3_exec( db, "commit transaction", 0, 0, &zErrorMsg ); //提交事务

result = sqlite3_exec( db, "rollback transaction", 0, 0, &zErrorMsg ); //回滚事务



5. Core Data 苹果自带的数据管理工具 (底层是SQLite3)
数据持久化存储
数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型
名词解释

(1)NSManagedObjectContext(被管理的数据上下文)

操作实际内容(操作持久层)

作用:插入数据,查询数据,删除数据

(2)NSManagedObjectModel(被管理的数据模型)

数据库所有表格或数据结构,包含各实体的定义信息

作用:添加实体的属性,建立属性之间的关系

操作方法:视图编辑器,或代码

(3)NSPersistentStoreCoordinator(持久化存储助理)

相当于数据库的连接器

作用:设置数据存储的名字,位置,存储方式,和存储时机

(4)NSManagedObject(被管理的数据记录)

相当于数据库中的表格记录

(5)NSFetchRequest(获取数据的请求)

相当于查询语句

(6)NSEntityDescription(实体结构)

相当于表格结构

(7)后缀为.xcdatamodeld的包

里面是.xcdatamodel文件,用数据模型编辑器编辑

编译后为.momd或.mom文件
(8)NSAttributeDescription 
 实体的attribut 
(9)NSRelationshipDescription 
指代实体间的relationship
(10)NSFetchedPropertyDescription 
 fetched属性

依赖关系
 


主要由以下几个类组合使用
//获取管理对象 后缀名为xcdatamodeld的Core Data文件做以下调用

NSURL *modelURL = [[NSBundlemainBundle] URLForResource:@"Core_Data_Peristence"withExtension:@"momd"];

NSManageObjectModel *model = [[NSManageObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator
alloc] initWithManageObjectModel:];
//设置数据底层的存储类型 和 文件名
NSURL *url= [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] LastObject]]; 
NSURL *mUrl = [url URLByAppendingPathComponent:@"core_data_persitence.sqlite"];

[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:mUrl options:nil error:nil];
//创建对象管理上下文并关联数据

NSManagedObjectContext *context = [[NSManageObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];


NSError *error;
//创建一个抓取数据的对象管理

NSFetchRequest *request = [[NSFetchRequest alloc] init];
//创建一个实体对象描述 ,相当于选择一个数据库里的表Line

NSEntityDescription *entityDescription = [NSEntityDescription

entityForName:@"Line"

inManagedObjectContext:context];

//设置抓取数据的条件筛选

NSPredicate *pred = [NSPredicate predicateWithFormat:@"name = %s", @"xukai"];

//结合表和条件准备开始抓取

[request setEntity:entityDescription];

[request setPredicate:pred];

//用来保存抓取出来的结果

NSmanagedObject* object = nil;

NSArray *objects = [context executeFetchRequest:request error:&error];

if( [objects count] > 0 )

object = [objects objectAtIndex:0];

else

object = [NSEntityDescription

insertNewObjectForEntityForName:@"Line"

inManagedObjectContext:context];

[object setValue:29 forKey:@"age"];

[object setValue:1 forKey:@"sex"];

[context save:&error];
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: