iOS中可以有四种持久化数据的方式:属性列表、对象归档、SQLite3、和Core Data。
一、关于属性列表的使用
iOS应用程序采用沙盒原理设计,每个应用程序都有自己的3个目录(Documents,Library,tmp),互相之间不能访问。
Documents存放应用程序的数据。
Library目录下面还有Preferences和Caches目录,Preferences目录存放应用程序的使用偏好,Caches目录与Documents很相似,可以存放应用程序的数据。
tmp目录提供应用程序存储临时文件。
//获得应用程序的Documents文件夹
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
//获取文件的完整路径
NSString* filename = [myDocPath stringByAppendingPathComponent:@"properties.plist"];
//获取tmp目录
NSString* tempPath = NSTemporaryDirectory();
//获取文件的完整路径
NSString* tempFile = [tempPath stringByAppendingPathComponent:@"properties.plist"];
实例:
点击save按钮,将文本框的内容保存到Documents文件夹下得properties.plist文件中。
- (IBAction)save:(id)sender{
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMark,YES);
NSString* myDocPath = [myPath objectAtIndex:0];
NSString* filePath = [myDocPath stringByAppendingPathComponent:@"properties.plist"];
NSMutableArray* data = [[[NSMutableArray alloc] init] autorelease];
[data addObject:textField.text];
[data writeToFile:filePath atomically:YES];
}
点击load按钮,将Documents文件夹下properties.plist文件的内容显示到文本框中。
- (IBAction)load:(id)sender{
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMark,YES);
NSString* myDocPath = [myPath objectAtIndex:0];
NSString* filePath = [myDocPath stringByAppendingPathComponent:@"properties.plist"];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSMutableArray* data = [[[NSMutableArray alloc] initWithContentsOfFile:filePath] autorelease];
textField.text = [data objectAtIndex:0];
}
}
二、对象归档
“归档”是值另一种形式的序列化,对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们,只要在类中实现的每个属性都是基本数据类型(int或者float)或都是符合NSCoding协议的每个类的实例,你就可以对你的对象进行完整的归档。
//实现NSCoding协议,有两个方法:
- (void)encodeWithCoder:(NSCoder*)aCoder;//将对象写入到文件中
- (id)initWithCoder:(NSCoder*)aDecoder;//文件中的数据读入到对象中
//实现NSCopying协议,有一个方法:
- (id)copyWithZone:(NSZone*)zone;//复制对象
实例:
创建一个Student类(遵循NSCoding、NSCopying协议),属性值有studentId,studentName,studentClass
- (void)encodeWithCoder:(NSCoder*)aCoder{
[aCoder encodeObject:studentId forKey:@"studentId"];
[aCoder encodeObject:studentName forKey:@"studentName"];
[aCoder encodeObject:studentClass forKey:@"studentClass"];
}
- (id)initWithCoder:(NSCoder*)aDecoder{
self.studentId = [aDecoder decodeObjectForKey:@"studentId"];
self.studentName = [aDecoder decodeObjectForKey:@"studentName"];
self.studentClass = [aDecoder decodeObjectForKey:@"studentClass"];
return self;
}
- (id)copyWithZone:(NSZone*)zone{
Student* student = [Student allocWithZone:zone];
student.studentId = self.studentId;
student.studentName = self.studentName;
student.studentClass = self.studentClass;
return student;
}
然后在视图控制器类中有三个文本框,名为“_idText,_nameText,_classText"
点击save按钮,将三个文本框的值存入到文件中
- (IBAction)save:(id)sender{
NSArray* myPaths = NSSearchPathDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMark,YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* filename = [myDocPath stringByAppendingPathComponent:@"student.archive"];
//以上是获取文件的路径及要使用的文件
//声明一个Student对象,将三个文本框的值赋给Student对象的三个属性值
Student* student = [[[Student alloc] init] autorelease];
student.studentId = _idText.text;
student.studentName = _nameText.text;
student.studentClass = _classText.text;
//将对象存储到文件中需要使用NSKeyedArchiver对象,而创建NSKeyedArchiver对象,需要NSMutableData对象,把要存储的对象存储到data中,所以。。。
NSMutableData* theData = [NSMutableData data];
NSKeyedArchiver* archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:theData] autorelease];
[archiver encodeObject:student forKey:@"student"];
[archiver finishEncoding];
[theData writeToFile:filename atomically:YES];//将数据写入到文件中
}
点击load按钮,把文件中的内容显示到三个文本框中
- (IBAction)load:(id)sender{
//先获取文件的路径
NSArray* myPaths = NSSearchPathDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMark,YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* filename = [myDocPath stringByAppendingPathComponent:@"student.archive"];
//把文件中的内容保存到NSData中
NSData* theData = [NSData dataWithContentsOfFile:filename];
//使用theData对象,来创建NSKeyedUnarchiver对象
NSKeyedUnarchiver* unArchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:theData] autorelease];
//然后解档,用Student对象接收
Student* student = [unArchiver decodeObjectForKey:@"student"];
//最后给三个文本框进行赋值
_idText.text = student.studentId;
_nameText.text = student.studentName;
_classText.text = student.studentClass;
}
三、SQLite3(数据库)
使用SQLite3的时候需要在framework框架下添加libsqlite3.dylib类库。
包含头文件import "sqlite3.h",定义一个数据库指针sqlite3* db;
在Documents文件夹下创建数据库:
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMark,YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* filename = [myDocPath stringByAppendingPathComponent:@"data.sqlite3"];
//打开数据库sqlite3_open。
//创建数据库表和执行SQL语句sqlite3_exec。
//释放资源sqlite3_close。
//下面代码是创建一个表格:
if(sqlite3_open([filename UTF8String],&db) != SQLITE_OK){
//在sqlite3中的函数都是使用C字符串,[filename UTF8String]是将NSString类型的字符串转换成C字符串。该函数返回SQLITE_OK,表明打开成功。
sqlite3_close(db);
NSAssert(NO,@"数据库打开失败");
}else{
char* err;
//创建一条sql语句,功能是建立一个表,表名是student,三列为_idText,_nameText,_classText
NSString* createSQL = [NSString stringWithFormat:@"create table if not exists %@(%@ TEXT primary key,%@ TEXT,%@ TEXT);",@"student",@"idText",@"_nameText",@"_classText"];
if(sqlite3_exec(db,[createSQL UTF8String],NULL,NULL,&err) != SQLITE_OK){
//sqlite_exec是执行任何不带返回值的sql语句,第二个参数是要执行的sql语句,第三个参数要回调的函数,第四个参数是回调函数的参数,第五个参数是执行出错的字符串。
sqlite3_close(db);
NSAssert(NO,@"建表失败");//断言函数,当断言失败时打印信息。
}
sqlite3_close(db);
}
/*
预处理sql语句sqlite3_prepare_v2(1,2,3,4,5);
第一个参数是sqlite3的指针,第二个参数是sql语句(c字符串),第三个参数是“-1”(代表是全部的sql字符串),第四个参数是sqlite3_stmt指针的地址,第五个参数是sql语句没有被执行的部分语句。
绑定参数sqlite3_bind_text(1,2,3,4,5);
第一个参数是sqlite3_stmt的指针,第二个参数为序号(从1开始),第三个参数是字符串值,第四个参数为字符串的长度,第五个参数为一个函数指针,SQLITE3执行完操作后回调此函数,通常用于释放字符串占用的内存。
执行语句sqlite3_step(statement)
释放资源sqlite3_finalize和sqlite3_close
*/
//下面代码是往表格中插入数据
当数据库打开成功之后
NSString* sqlStr = [NSString stringWithFormat:@"insert or replace into %@(%@,%@,%@) values(?,?,?)",@"student",@"_idText",@"_nameText",@"_classText"];
sqlite3_stmt* statement;
if(sqlite3_prepare_v2(db,[sqlStr UTF8String],-1,&statement,NULL) == SQLITE_OK){ //执行成功之后,开始绑定参数
sqlite3_bind_text(statement,1,[_idText.text UTF8String],-1,NULL);
sqlite3_bind_text(statement,2,[_nameText.text UTF8String],-1,NULL);
sqlite3_bind_text(statement,3,[_classText.text UTF8String],-1,NULL);
//开始执行
if(sqlite3_step(statement) != SQLITE_DONE){//判断是否执行完成sql语句执行
NSAssert(NO,@"插入失败");
}
}
sqlite3_finalize(statement);//释放资源
sqlite3_close(db); //释放资源
//下面代码是把数据库文件中的数据显示到文本框上来
当打开数据库成功之后
NSString* sqlStr = [NSString stringWithFormat:@"select %@,%@,%@ from %@ where %@ = ?",@"_idText",@"_nameText",@"_classText",@"student",@"_idText"];
sqlite3_stmt* statement;
//预处理过程
if(sqlite3_prepare_v2(db,[sqlStr UTF8String],-1,&statement,NULL) == SQLITE_OK){
//绑定参数
sqlite3_bind_text(statement,1,"1000",-1,NULL);//这里的“1000”是_idText的值
//执行
while(sqlite3_step(statement) == SQLITE_ROW){
//单步执行并判断sql语句执行的状态
char* field1 = (char*)sqlite3_column_text(statement,0);
//sqlite3_column_text(statement,0) 取出字段值,第二个参数是列的顺序,从0开始。
NSString* field1Str = [[[NSString alloc] initWithUTF8String:field1] autorelease];
_idText.text = field1Str;
char* field2 = (char*)sqlite3_column_text(statement,1);
NSString* field2Str = [[[NSString alloc] initWithUTF8String:field2] autorelease];
_nameText.text = field2Str;
char* field3 = (char*)sqlite3_column_text(statement,2);
NSString* field3Str = [[[NSString alloc] initWithUTF8String:field3] autorelease];
_classText.text = field3Str;
}
}
sqlite3_finalize(statement);
sqlite3_close(db);