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);