iOS提供的的数据持久化的方法大体上有下面几种:
1、属性列表
2、对象归档
3、SQLite3
4、Core Data
5、其它方式:存储文件的方式等
详细介绍请参见具体代码和注释
一、属性类表
/*
属性列表
NSUserDefaults类的使用和NSkeyedArchiver有很多相似之处,但是查看NSUserDefaults的定义可以看出,
NSUserDefaults直接继承自NSObject而NSKeyedArchiver继承自NSCoder.这意味着NSKeyedArchiver实际上
是个归档类持久化的类,也就是可以使用NSCoder类的[encodeObject:(id)objv forKey:(NSString *)key]
方法来数据进行持久存储。
*/
-(void) forNSuserDefaults{
NSString *strOne=@"PersistentData1";
NSString *strTwo=@"PersistentData2";
NSMutableArray *persistentArray=[[NSMutableArray alloc]init];
[persistentArray addObject:strOne];
[persistentArray addObject:strTwo];
// archive存储数据
NSUserDefaults *persistentDefaults=[NSUserDefaults standardUserDefaults];
[persistentDefaults setObject:persistentArray forKey:@"myDefault"];
NSString *descriptionDefault=[persistentDefaults description];
NSLog(@"NSUserDefaults description is %@",descriptionDefault);
[persistentDefaults release];
[persistentArray release];
}
-(void) forNSuserUndefaults{
// unarchive取数据
NSUserDefaults *persistentDefaults=[NSUserDefaults standardUserDefaults];
NSArray *UnpersistentArray=[persistentDefaults objectForKey:@"myDefault"];
NSString *UnstrOne=[UnpersistentArray objectAtIndex:0];
NSString *UnstrTwo=[UnpersistentArray objectAtIndex:1];
NSLog(@"UnstrOne= %@,UnstrTwo= %@",UnstrOne,UnstrTwo);
[UnpersistentArray release];
[persistentDefaults release];
}
二 、对象归档
/*
对象归档NSKeyedArchiver和 NSKeyedUnarchiver
这种方式有点类似于Android中的SharePreference方式的存储,作用范围在整个项目中,只有根据myFilename都是可以取到的。
iphone 和 symbian 3rd一样,会为每个应用程序生成一个私有的目录,这个目录位于
User/sundfsun2009/Library/Application Support/iphone Simulator/User/Application下,并随即生成一个数字字母串作为目录名,在每一次启
动应用程序时,这个字母数字串都是不同与上一次的,上一次的应用程序目录信息被转换成名为:.DS_Store隐藏文件
通常使用Documents目录进行数据持久化的保存,而这个Documents目录可以通过NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserdomainMask,YES)得到
*/
-(void) forNSKeyedArchiver{
//第一步:定义并初始化一个数组即被保存的数据。
NSString *strOne=@"PersistentData1";
NSString *strTwo=@"PersistentData2";
NSArray *persistentArray=[NSArray arrayWithObjects:strOne,strTwo,nil];
//第二步:生成 .rtf完整的文件路径名
NSArray *pathArray=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSAllDomainsMask,YES);//第二个参数是个枚举值 NSUserDomainMask和NSAllDomainsMask可以获取到目录数为1,其余的皆为0
int pathLen=[pathArray count];
NSLog(@"path number is %d",pathLen);//1
NSString *filePath;
for (int i=0; i<pathLen; i++) {
filePath=[pathArray objectAtIndex:i];
NSLog(@"%d path is :%d",i,filePath);//这里输出: 0 path is :/Users/sundfsun2009/Library/Application Support/iPhone Simulator/User/Applications/C93DC783-F137-4660-AE5A-08C3E11C774B/Documents
}
NSString *myFilename=[filePath stringByAppendingPathComponent:@"myFile.rtf"];//上面的路径PATH/myFile.rtf
NSLog(@"myfile\'s path is : %@",myFilename);
//第三步:保存数组数据到myFile.rtf中去,这里的myFilename是路径+文件名
[NSKeyedArchiver archiveRootObject:persistentArray toFile:myFilename];//把这个数组添加到myFile.rtf中去
//总结:每次应用程序启动时生成的数字字母串目录名字并不一样。
//在调用[NSKeyedArchiver archiveRootObject:persistentArray toFile:myFilename]方法前,文件myFile.rtf并每生成,
//只有在调用此方法后才产生相应的文件。
}
/*
演示的取数据的操作
*/
-(void) forNSKeyedUnarchiver{
NSArray *pathArray=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSAllDomainsMask,YES);//第二个参数是个枚举值 NSUserDomainMask和NSAllDomainsMask可以获取到目录数为1,其余的皆为0
int pathLen=[pathArray count];
NSLog(@"path number is %d",pathLen);//1
NSString *filePath;
for (int i=0; i<pathLen; i++) {
filePath=[pathArray objectAtIndex:i];
NSLog(@"%d path is :%d",i,filePath);//0 path is :/Users/sundfsun2009/Library/Application Support/iPhone Simulator/User/Applications/C93DC783-F137-4660-AE5A-08C3E11C774B/Documents
}
NSString *myFilename=[filePath stringByAppendingPathComponent:@"myFile.rtf"];//上面的路径PATH/myFile.rtf
NSLog(@"myfile\'s path is : %@",myFilename);
//第三步:保存数组数据到myFile.rtf中去,这里的myFilename是路径+文件名
//[NSKeyedArchiver archiveRootObject:persistentArray toFile:myFilename];//把这个数组添加到myFile.rtf中去
NSArray *unarchiveArray = [NSKeyedUnarchiver unarchiveObjectWithFile:myFilename];
NSString *UnstrOne = [unarchiveArray objectAtIndex:0];
NSString *UnstrTwo = [unarchiveArray objectAtIndex:1];
NSLog(@"UnstrOne = %@,UnstrTwo = %@",UnstrOne,UnstrTwo);
}
关于sqlite3数据库在iphone项目中的应用大体上有下面几个步骤:
1、 在新建的项目中右击Frameworks文件夹,添加libsqlit3.dylib库;
2、 在.h的头文件中声明一个类型为sqlite3的变量;// 这里要特别说明一下这个变量,开始的时候是为NULL的,数据库打开之后就不为空了,不知道sqlite3中对这中结构的设计是出于什么目的,暂且记住这么用吧,如何你对它有更好的理解不妨告诉我一下。
sqlite3 *_database;
3、 获取Documents文件夹的路径,这个其实就是数据库文件最终存在的目录,新建时也要建在这目录下;
- (NSString *)getDocuments{
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];// 这个kFilename 是你为数据库起的名字
}
4、 创建并打开数据库
/*
如果数据库存在,则用sqlite3_open直接打开(不要担心,如果数据库不存在sqlite3_open会自动创建)
打开数据库,这里的[path UTF8String]是将NSString转换为C字符串,因为SQLite3是采用可移植的C(而不是
Objective-C)编写的,它不知道什么是NSString.
*/
- (void)openDB {
//获取数据库路径
NSString *path = [self getDocuments];
if(sqlite3_open([pathUTF8String], &_database) !=SQLITE_OK) {
//如果打开数据库失败则关闭数据库
sqlite3_close(self._database);
}
}
5、创建表
//创建表
- (BOOL) createTableMath:(sqlite3*)db {
//这句是大家熟悉的SQL语句
char *sql ="create table if not exists testTable(ID INTEGER PRIMARY KEY AUTOINCREMENT, testID int,testValue text)";
sqlite3_stmt *statement;
//sqlite3_prepare_v2接口把一条SQL语句解析到statement结构里去.使用该接口访问数据库是当前比较好的的一种方法
//第三个参数我写的是-1,这个参数含义是前面 sql 语句的长度。如果小于0,sqlite会自动计算它的长度(把sql语句当成以\0结尾的字符串)。
//第四个参数是sqlite3_stmt 的指针的指针。解析以后的sql语句就放在这个结构里。
//第五个参数为nil就可以了。
//如果这个函数执行成功(返回值是 SQLITE_OK 且 statement 不为NULL ),那么下面就可以开始插入二进制数据。
//如果SQL语句解析出错的话程序返回
NSInteger sqlReturn =sqlite3_prepare_v2(_database, sql, -1, &statement,nil);
if(sqlReturn !=SQLITE_OK) {
NSLog(@"Error: failed to prepare statement:create test table");
returnNO;
}
NSLog(@"..create test table successful..>>");
//执行statement语句
int success =sqlite3_step(statement);
//释放sqlite3_stmt
sqlite3_finalize(statement);
//执行SQL语句失败
if ( success !=SQLITE_DONE) {
NSLog(@"Error: failed to dehydrate:create table test");
returnNO;
}
NSLog(@"Create table 'testTable' successed.");
returnYES;
}
// 插入数据 方式一
-(BOOL)insertRecord1{
if ([selfopenDB]) {
sqlite3_stmt *statement;
staticchar *sql="insert into testTable(testID,testValue) values(?,?);";// ?表示未定的值,它的值等下才会插入
int success2=sqlite3_prepare_v2(_database, sql, -1, &statement, NULL);
if (success2!=SQLITE_OK) {
sqlite3_close(_database);
returnNO
}
//这里的1,2代表第几个问号
sqlite3_bind_int(statement,1, @"1");
sqlite3_bind_text(statement,2, @"test value", -1,SQLITE_TRANSIENT);
success2=sqlite3_step(statement);
sqlite3_finalize(statement);
if (success2!=SQLITE_OK) {
sqlite3_close(_database);
returnNO;
}
sqlite3_close(_database);
returnYES;
}
returnNO;
}
大多数情况下推荐这种方式 比较简洁
插入数据方式 二
-(void) insertRecord2:(NSString *)tableName withField1:(NSString*) field1 field1Value:(NSString*) field1Value withField2:(NSString*)field2 field2Value:(NSString*) field2Value{
NSString *sql=[NSString stringWithFormat:@"insert or replace into '%@' ('%@' ,'%@') values ('%@','%@')",tableName,field1,field1Value,field2,field2Value];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err)!=SQLITE_OK) {
sqlite3_close(db);
NSAssert(0,"插入记录失败");
}
}
// 查询记录
-(NSMutableArray*)getResult:(int)searchID{
NSMutableArray *array=[NSMutableArray arrayWithArray:10];
if ([selfopenDB]) {
sqlite3_stmt *statement=nil;
char *sql="select testID,testValue from testTable where testID=?";
if (sqlite3_prepare_v2(_database, sql, -1, &statement, NULL)!=SQLITE_OK) {
returnNO;
}else {
sqlite3_bind_int(statement,1, searchID);// 这里的1是代表的sql语句里面的那个问号
while (sqlite3_step(statement)==SQLITE_ROW) {// 便利结果集,这都是sqlite3自己的方法。
sqlTestList* sqlList=[[sqlTestList alloc ]init];
sqlList.sqlID=sqlite3_column_int(statement,0);//取出相应字段的值,数据库中也是integer类型
char *strText=(char*)sqlite3_column_text(statement,1);//这里要转换一下格式
sqlList.sqlText=[NSStringstringWithUTF8String:strText];
[arrayaddObject:sqlList];
[sqlListrelease];
}
}
sqlite3_finalize(statement);
sqlite3_close(_database);
}
return [array retain];
}