数据持久化 coredata、sqlite、fmdb和sqlitepersistentobject
来源:互联网 发布:越南旅游 知乎 编辑:程序博客网 时间:2024/04/30 13:17
在ios开发过程中,经常需要用到数据持久化工作。对于基本的配置信息等,NSUserDefault已经可以满足要求,但是对于大部分需要存储的信息,主要的方式有coredata建模或者sqlite写数据库的方法进行存储。现在针对coredata、sqlite以及常用的sqlite封装库进行研究和学习。
从中可以看出,sqlite最快,基本都只用fmdb以及coredata等的一半时间。接下来我们逐个解析相关技术/库的操作以及使用。
- // initilize
-
NSURL*modelURL = [[NSBundle mainBundle] URLForResource:@"coreData"withExtension:@"momd"]; -
coreDataModel= [[NSManagedObjectModel alloc]initWithContentsOfURL:modelURL]; - 我们可以理解为,coreDataModel就代表了该模型。
- 接下来,我们需要考虑,有了模型后,数据最终应该存在哪里?答案是:文件。接下来我们有另外一个类来管理模型跟文件之间的对应关系:
- [code]NSString* strInfoPath = [[NSHomeDirectory()stringByAppendingPathCom
ponent:@"Documents"]stringByAppendingPathCom ponent:@"coreData.sqlite"]; - coreDataCoordinator = [[NSPersistentStoreCoordin
ator alloc]initWithManagedObjectMod el:coreDataModel]; -
- [coreDataCoordinatoraddPersistentStoreWithTy
pe:NSSQLiteStoreType configuration:nilURL:[NSURL fileURLWithPath:strInfoPath] options:nilerror:nil]; - OK,现在文件<->模型之间的映射关系也有了。那么接下来我们就需要去对模型数据库进行读写操作等。自然,有一个上下文用来执行/处理相关数据信息:
- [code]// 对context进行操作
-
coreDataContext= [[NSManagedObjectContext alloc]init]; -
[coreDataContextsetPersistentStoreCoordi nator:coreDataCoordinator]; - 我们尝试去插入一条数据:
- [code]NSManagedObject* object = [NSEntityDescriptioninsertNewObjectForEntity
ForName:@"TestCoreData"inManagedObjectContext:coreDataContext]; -
- [object setValue:[NSNumber numberWithInt:data->intType]forKey:@"intType"];
- [object setValue:[NSNumber numberWithFloat:data->floatType]forKey:@"floatType"];
- [object setValue:[NSNumbernumberWithDouble:data->doubleType]forKey:@"doubleType"];
- [object setValue:[NSStringstringWithUTF8String:data->testString]forKey:@"stringType"];
添加完毕数据后,内存中模型已经有添加的数据了。但是文件中还没有同步进去,那么我们调用:
[coreDataContext save:nil];
关于其他修改、删除等操作,以及coredata中的releationship操作等,可以参考附件程序或查阅相关其他资料。
【sqlite】
- - (IBAction)onBtnSqlite:(id)sender {
-
-
//初始化数据库要保存的地方,如果存在则删除 -
NSString*strSQLiteFilePath = [[NSHomeDirectory()stringByAppendingPathCom ponent:@"Documents"]stringByAppendingPathCom ponent:@"sqlite.sqlite"]; -
-
BOOLbIsDir = FALSE; -
if([[NSFileManager defaultManager] fileExistsAtPath:strSQLiteFilePathisDirectory:&bIsDir]){ -
[[NSFileManagerdefaultManager] removeItemAtPath:strSQLiteFilePatherror:nil]; -
} -
-
sqlite3*sqlite = NULL; -
-
//首先打开数据库路径,如果不存在则创建 -
if(SQLITE_OK != sqlite3_open([strSQLiteFilePath UTF8String],&sqlite)) { -
NSLog(@"sqlite3:open error..."); -
} -
-
//create table -
//创建表,主要就是sql语句 -
NSString*strCreateTable = @"CREATE TABLE TESTCOREDATA(intType INTEGER,floatType FLOAT, doubleType DOUBLE, stringTypeVARCHAR(256))"; -
if(sqlite3_exec(sqlite, [strCreateTable UTF8String], nil, nil, nil)!= SQLITE_OK) { -
NSLog(@"sqliteCreate table error..."); -
} -
//接下来是生成10w条测试数据 -
NSArray*arrayTest = [selfarrayWithData:100000]; -
NSLog(@"Beforesave..."); -
//!!!这里很重要,将所有的insert操作作为一个transaction操作,这样避免每次insert的时候都去写文件,导致IO时间拖慢整个数据插入操作 -
NSString*strBegin = @"BEGINTRANSACTION"; -
sqlite3_exec(sqlite,[strBegin UTF8String], NULL, NULL,NULL); -
//遍历数据并插入,就是普通的sql语句操作 -
for(NSValue* value inarrayTest) -
{ -
Data*data = [valuepointerValue]; -
-
NSString*strSQLInsert = [NSString stringWithFormat:@"INSERT INTOTESTCOREDATA(intType, floatType, doubleType, stringType) values(%d,%f, %lf, '%s')", data->intType, data->floatType,data->doubleType,data->testString]; -
-
if(SQLITE_OK != sqlite3_exec(sqlite, [strSQLInsert UTF8String], NULL,NULL, NULL)) -
{ -
constchar* errormsg =sqlite3_errmsg(sqlite); -
NSLog(@"execError..."); -
} -
-
free(data); -
} -
-
//提交所有的插入操作 -
NSString*strEnd = @"COMMIT"; -
sqlite3_exec(sqlite,[strEnd UTF8String], NULL, NULL,NULL); -
-
NSLog(@"EndSave..."); -
-
-
//不使用的时候关闭即可 -
sqlite3_close(sqlite); -
sqlite= NULL; -
- }
sqlite非常直观,并且依赖于sql语句,所以sqlite的有点在于灵活性高,上手简单并易于理解。缺点就是带来了很多底层数据库的操作,一般都需要自己再去进行数据建模并进行封装使用。
相关读写步骤也很简单:
- - (IBAction)onBtnSqliteRead:(id)sender {
-
sqlite3*sqlite = NULL; -
-
NSString*strSQLiteFilePath = [[NSHomeDirectory()stringByAppendingPathCom ponent:@"Documents"]stringByAppendingPathCom ponent:@"sqlite.sqlite"]; -
-
BOOLbIsDir = FALSE; -
if(![[NSFileManager defaultManager]fileExistsAtPath:strSQLiteFilePath isDirectory:&bIsDir]){ -
NSLog(@"SqliteOpen Error....File NOtexist..."); -
return; -
} -
-
if(SQLITE_OK != sqlite3_open([strSQLiteFilePath UTF8String],&sqlite)) -
{ -
NSLog(@"sqliteopen error..."); -
return; -
} -
-
NSString*strSQL = @"select * fromTESTCOREDATA"; -
-
sqlite3_stmt*stmt; -
//将对应的操作信息跟stmt进行bind,如果有相关条件可以在prepare之后进行调整 -
sqlite3_prepare_v2(sqlite,[strSQL UTF8String], -1, &stmt,NULL); -
//获取执行SQL的返回结果 -
while(SQLITE_ROW == sqlite3_step(stmt)){ -
intnIntType = sqlite3_column_int(stmt,0); -
floatfloatType = sqlite3_column_double(stmt,1); -
doubledoubleType = sqlite3_column_double(stmt,2); -
constunsigned char* strTest = sqlite3_column_text(stmt,3); -
-
break; -
} -
-
-
-
sqlite3_close(sqlite); - }
【FMDB】
要使用fmdb,将获取到的包中src下的文件(除了fmdb.m)拖到自己工程中(最好用一个group管理起来),然后添加libsqlite3.0.dylib即可。
照例我们先来看下fmdb的基础用法:
- NSString* strSQLiteFilePath = [[NSHomeDirectory()stringByAppendingPathCom
ponent:@"Documents"]stringByAppendingPathCom ponent:@"fmdb.sqlite"]; -
-
BOOLbIsDir = FALSE; -
if([[NSFileManager defaultManager] fileExistsAtPath:strSQLiteFilePathisDirectory:&bIsDir]){ -
[[NSFileManagerdefaultManager] removeItemAtPath:strSQLiteFilePatherror:nil]; -
} -
-
FMDatabase*db = [FMDatabasedatabaseWithPath:strSQLiteFilePath]; -
-
if(![db open]) { -
NSLog(@"dbOpen Error..."); -
} -
-
NSString*strCreateTable = @"CREATE TABLE TESTCOREDATA(intType INTEGER,floatType FLOAT, doubleType DOUBLE, stringTypeVARCHAR(256))"; -
-
[dbexecuteUpdate:strCreateTable]; -
-
NSLog(@"begin"); -
[dbbeginTransaction]; -
-
NSArray*arrayTest = [selfarrayWithData:100000]; -
-
for(NSValue* value inarrayTest) -
{ -
Data*data = [valuepointerValue]; -
-
NSString*strSQLInsert = [NSString stringWithFormat:@"INSERT INTOTESTCOREDATA(intType, floatType, doubleType, stringType) values(%d,%f, %lf, '%s')", data->intType, data->floatType,data->doubleType,data->testString]; -
[dbexecuteUpdate:strSQLInsert]; -
free(data); -
} -
-
[dbcommit]; -
NSLog(@"end..."); -
-
[dbclose]; -
db= nil;
fmdb使用比直接调用sqlite要省略很多代码和相关参数(估计让很多人很头疼),整个使用过程感觉就是四个字:酣畅淋漓。只将必要的一些关键操作需要给出参数。符合大部分对性能要求不高的场合,非常方便。fmdb针对读取操作也一样方便,这里就不多讲。接下来我们看看fmdb中其他几个文件的用途,有几个比较有趣的东西可以细说。
在我们拿到的src中,还有部分文件我们在基本的使用场景中很少用到的:
FMDatabaseAdditions.*文件,我们可以打开h文件看下:
-
-
- - (int)intForQuery:(NSString*)query,...;
-
-
-
- - (long)longForQuery:(NSString*)query, ...;
- [queue inDatabase:^(FMDatabase *db){
-
//操作db -
}]; - 而由queue自己去保证执行的先后顺序和唯一性,避免同时操作时产生冲突等。
- FMDatabasePool*则提供了一个db池,每一个db实力都会放在FMDatabasePool的池中,使用完成后归还db即可,sqlite相关的生命周期都由db池进行管理。避免经常性的open和close操作。
- 具体的相关细节可以参考fmdb的源码。
- 【sqlitepersistentobject】
-
sqlitepersistentobject库是基于ORM模型编写,将没一条数据都封装成对应的一个对象,而且完全屏蔽相关表名、文件名等信息,采用sqlitepersistentobject时,将所有的信息都屏蔽在实现细节后面。操作的时候只要操作每一个对象即可。 - sqlitepersistentobject相关下载路径:https://code.google.com/p/sqlitepersistentobjects/
- 同样,要使用sqlitepersistentobject,首先将库下载下来后,将src中相关文件拉入到自己的工程。并添加libsqlite3.0.dylib。因为sqlitepersistentobject底层也是用的sqlite进行的操作。
- 先来看下基础的数据插入部分:
- [code]#import
- #import"SQLitePersistentObject.h"
-
- @interface ZJSqlitePersistentobject
sPerson :SQLitePersistentObject - {
-
intintType; -
floatfloatType; -
doubledoubleType; -
NSString*stringType; - }
-
- @property(assign, nonatomic) intintType;
- @property(assign, nonatomic) floatfloatType;
- @property(assign, nonatomic) doubledoubleType;
- @property(copy, nonatomic) NSString*stringType;
- @end
首先我们有一个数据类,继承自SQLitePersistentObject,每一个ZJSqlitePersistentobject
接下来,我们添加一批ZJSqlitePersistentobject
- NSArray* arrayTest = [selfarrayWithData:1000];
-
-
NSLog(@"begin..."); -
-
for(NSValue* value inarrayTest) -
{ -
Data*data = [valuepointerValue]; -
-
ZJSqlitePersistentobject sPerson*person = [[ZJSqlitePersistentobject sPerson alloc]init]; -
person.intType= data->intType; -
person.floatType= data->floatType; -
person.doubleType= data->doubleType; -
person.stringType= [NSStringstringWithUTF8String:data->testString]; -
-
[personsave]; -
[personrelease]; -
free(data); -
} -
-
//[ZJSqlitePersistentobject sPersonclearCache]; -
-
[ZJSqlitePersistentobject sPersonclearCache]; -
-
NSLog(@"end...");
可以从插入过程中看到,整个操作过程中完全屏蔽了相关sql语句、表结构等细节。非常方便简单,不过sqlitepesistentobject只支持基础数据类型和实现了NSCoding等相关类,由此,对于相关集合类型(NSArray,NSSet,NSDictionary)等是不支持的。关于sqlitepersistentobject的其他细节,可以参考sqlitepersistentobject源码。
【总结】
综合比较coredata、sqlite、fmdb和sqlitepersistentobject等四种数据永久化方式,个人认为:
1、如果只是基础数据类型并且对sql不熟悉,用sqlitepersistenttobject是最理想的,我们需要的是数据,sqlitepersistentobject需要你面对的也是一条一条的数据。
2、如果需要操作一般的比较复杂的数据库以及类型,个人推荐用fmdb,非常方便和便于操作,而且sqlite本身还支持对数据加密的借口。
3、如果需要很好的性能,可以使用sqlite并自己封装相关接口。
4、如果需要基本的数据模型,并且对xcode可视化情有独钟的话,可以使用coredata->datamodel等。
- 数据持久化 coredata、sqlite、fmdb和sqlitepersistentobject
- 【数据存储】coredata、sqlite、fmdb和sqlitepersistentobject
- coredata、sqlite、fmdb和sqlitepersistentobject
- 【iOS开发】数据存储之coredata、sqlite、fmdb和sqlitepersistentobject
- 数据持久化-CoreData、SQLite、FMDB
- 数据持久化-CoreData、SQLite、FMDB
- Oc 数据持久化Plist、SQLite、CoreData、FMDB四种-demo
- 数据持久化 plist,CoreData,Sqlite
- ios开发学习笔记--数据持久化之数据库(SQLite.swift)和FMDB
- iOS XML JSON SQLite CoreData 数据持久化
- CoreData:数据持久化
- CoreData数据持久化
- IOS 数据持久化的NSKeyedArchiver CoreData FMDB几种方式的用法
- iOS 数据持久化-CoreData
- iOS 数据持久化 CoreData
- IOS学习:ios中的数据持久化初级(文件、xml、json、sqlite、CoreData)
- ios开发之数据的持久化存储机制NSuserDefault、Plist、archiver、Sqlite、coreData
- sqlite持久化封装框架for ios--sqlitepersistentobjects 和 fmdb
- andorid实例源码地址分享(一)
- 编程之美资格赛 大神与三位小伙伴
- 设置分割窗口背景色的简单方法
- DNS使用的是TCP协议还是UDP协议?
- 黑马程序员_java开发工具下载
- 数据持久化 coredata、sqlite、fmdb和sqlitepersistentobject
- POJ 1456 Supermarket
- 路考
- 8球胜负 2537
- 包含多集合的json反序列化
- 使用eclipse/STS maven遇到的问题
- Letter Combinations of a Phone Number
- WM_DRAWITEM与DrawItem()的讨论
- 路考口诀