轉載請註明出處,原文網址:http://blog.csdn.net/m_changgong/article/details/8284135
作者:張燕廣
實現的功能:1)演示使用sqlite3持久化數據。
關鍵詞:數據持久化 sqlite3 數據庫
1、將上一篇iPhone開發【二十二】數據持久化總結之第3篇歸檔(NSKeyedArchiver、NSKeyedUnarchiver)的工程拷貝一份,名稱修改爲Persistence-sqlite,工程結構如下:
Person類已經沒用了,可以刪掉。
2、爲工程添加sqlite3的庫libsqlite3.dylib,如下圖所示:
3、主要修改了ViewController類,ViewController.h如下:
#define kFileName @"archive"
#define kDataKey @"Data"
#define kSqliteFileName @"data.db3"
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property(nonatomic,retain)IBOutlet UITextField *name;
@property(nonatomic,retain)IBOutlet UITextField *gender;
@property(nonatomic,retain)IBOutlet UITextField *age;
@property(nonatomic,retain)IBOutlet UITextField *education;
-(NSString *)dataFilePath;
-(void)applicationWillResignActive:(NSNotification *)nofication;
@end
ViewController.m如下:
#import "ViewController.h"
#import "Person.h"
#import <sqlite3.h>
@implementation ViewController
@synthesize name,gender,age,education;
-(NSString *)dataFilePath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//return [documentsDirectory stringByAppendingPathComponent:kFileName];
return [documentsDirectory stringByAppendingPathComponent:kSqliteFileName];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
NSString *filePath = [self dataFilePath];
NSLog(@"filePath=%@",filePath);
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
//屬性列表
/*
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
name.text = [array objectAtIndex:0];
gender.text = [array objectAtIndex:1];
age.text = [array objectAtIndex:2];
education.text = [array objectAtIndex:3];
[array release];*/
//歸檔
/*
NSData *data = [[NSMutableData alloc]initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
Person *person = [unarchiver decodeObjectForKey:kDataKey];
[unarchiver finishDecoding];
name.text = person.name;
gender.text = person.gender;
age.text = person.age;
education.text = person.education;
[unarchiver release];
[data release];*/
//sqlite3
sqlite3 *database;
//打開數據庫
if(sqlite3_open([filePath UTF8String], &database)!=SQLITE_OK){//備註1
//數據庫打開失敗,關閉數據庫
sqlite3_close(database);
NSAssert(0,@"打開數據庫失敗");
}
char* errorMsg;
NSString *createSQL = @"CREATE TABLE IF NOT EXISTS PERSON (name TEXT PRIMARY KEY,gender TEXT,age TEXT,education TEXT);";
//創建表
if(sqlite3_exec(database, [createSQL UTF8String], NULL, NULL, &errorMsg)!=SQLITE_OK){//備註2
//創建表失敗,關閉數據庫
sqlite3_close(database);
NSAssert1(0, @"創建表失敗:%s", errorMsg);
}
//查詢表
NSString *querySQL = @"SELECT name,gender,age,education FROM PERSON ORDER BY name";
//執行查詢,遍歷查詢結果
sqlite3_stmt *statment;
if(sqlite3_prepare_v2(database, [querySQL UTF8String], -1, &statment, nil) == SQLITE_OK){//備註3
//查詢成功,執行遍歷操作
while(sqlite3_step(statment) == SQLITE_ROW){//備註4
const char* pName = (char*)sqlite3_column_text(statment, 0);//備註5
if(pName!=NULL){
self.name.text = [[NSString alloc]initWithUTF8String:pName];
}
char* pGender = (char*)sqlite3_column_text(statment, 1);
if(pGender!=NULL){
self.gender.text = [[NSString alloc]initWithUTF8String:pGender];
}
char* pAge = (char*)sqlite3_column_text(statment, 2);
if(pAge!=NULL){
self.age.text = [[NSString alloc]initWithUTF8String:pAge];
}
char* pEducation = (char*)sqlite3_column_text(statment, 3);
if(pEducation!=NULL){
self.education.text = [[NSString alloc]initWithUTF8String:pEducation];
}
}
sqlite3_finalize(statment);//備註6
}
//關閉數據庫
sqlite3_close(database);//備註7
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
[super viewDidLoad];
}
-(void)applicationWillResignActive:(NSNotification *)nofication{
//屬性列表
/*
NSMutableArray *array = [[NSMutableArray alloc]init];
[array addObject:name.text];
[array addObject:gender.text];
[array addObject:age.text];
[array addObject:education.text];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];*/
//歸檔
/*
Person *person = [[Person alloc]init];
person.name = name.text;
person.gender = gender.text;
person.age = age.text;
person.education = education.text;
NSMutableData *data = [[NSMutableData alloc]init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archiver encodeObject:person forKey:kDataKey];
[archiver finishEncoding];
[data writeToFile:[self dataFilePath] atomically:YES];
[person release];
[archiver release];
[data release];*/
//sqlite3
sqlite3 *database;
//打開數據庫
if(sqlite3_open([[self dataFilePath] UTF8String], &database)!=SQLITE_OK){
//數據庫打開失敗,關閉數據庫
sqlite3_close(database);
NSAssert(0,@"打開數據庫失敗");
}
char* errorMsg;
NSString *updateSQL = @"INSERT OR REPLACE INTO PERSON(name,gender,age,education) VALUES(?,?,?,?);";
//執行插入或更新操作
sqlite3_stmt *statment;
if(sqlite3_prepare_v2(database, [updateSQL UTF8String], -1, &statment, nil) == SQLITE_OK){
//綁定變量
sqlite3_bind_text(statment, 1, [self.name.text UTF8String], -1, NULL);//備註8
sqlite3_bind_text(statment, 2, [self.gender.text UTF8String], -1, NULL);
sqlite3_bind_text(statment, 3, [self.age.text UTF8String], -1, NULL);
sqlite3_bind_text(statment, 4, [self.education.text UTF8String], -1, NULL);
}
if(sqlite3_step(statment)!=SQLITE_DONE){
NSAssert1(0, @"更新表失敗:%s", errorMsg);
}
sqlite3_finalize(statment);
//關閉數據庫
sqlite3_close(database);
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.name = nil;
self.gender = nil;
self.age = nil;
self.education = nil;
}
-(void)dealloc{
[name release];
[gender release];
[age release];
[education release];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end
代碼解釋:
備註1:sqlite3_open():打開數據庫
在操作數據庫之前,首先要打開數據庫。
這個函數打開一個sqlite數據庫文件的連接並且返回一個數據庫連接對象。
第1個參數:數據文件路徑必須用C風格字符串(不能用NSString),[filePath UTF8String]將filePath轉換爲C風格字符串。
第2個參數:是返回的數據庫連接對象。
第1個參數:數據庫指針,是前面open函數得到的指針
第2個參數:const char *sql是一條sql 語句,以\0結尾。
第3個參數:sqlite3_callback 是回調,當這條語句執行之後,sqlite3會調用這個回調函數。
第4個參數:void*是一個指針,可以傳遞任何一個指針參數到這裏,這個參數最終會傳到回調函數裏面,如果不需要傳遞指針給回調函數,可以填NULL
備註3:sqlite3_prepare_v2():將sql文本轉換成一個準備語句(prepared statement)對象,同時返回這個對象的指針
第1個參數:數據庫指針,是前面open函數得到的指針
第2個參數:sql語句,必須是C風格字符串
第3個參數:如果該參數小於0,則函數取出zSql中從開始到第一個0終止符的內容;如果nByte不是負的,那麼它就是這個函數能從zSql中讀取的字節數的最大值。如果nBytes非負,zSql在第一次遇見’/000/或’u000’的時候終止
第4個參數:上面提到zSql在遇見終止符或者是達到設定的nByte之後結束,假如zSql還有剩餘的內容,那麼這些剩餘的內容被存放到pZTail中,不包括終止符
備註4:sqlite3_step()
這個過程用於執行有前面sqlite3_prepare創建的準備語句。這個語句執行到結果的第一行可用的位置。繼續前進到結果的第二行的話,只需再次調用sqlite3_setp()。繼續調用sqlite3_setp()直到這個語句完成,那些不返回結果的語句(如:INSERT,UPDATE,或DELETE),sqlite3_step()只執行一次就返回
備註5:sqlite3_column_text()
從結果集中獲取各列的值,需要注意的是:第一列的索引是0。
備註6:sqlite3_finalize()
這個過程銷燬前面被sqlite3_prepare創建的準備語句,每個準備語句都必須使用這個函數去銷燬以防止內存泄露。
在空指針上調用這個函數沒有什麼影響,同時可以在準備語句的生命週期的任一時刻調用這個函數:在語句被執行前,一次或多次調用
sqlite_reset之後,或者在sqlite3_step任何調用之後。
備註7:sqlite3_close()
關閉前面使用sqlite3_open打開的數據庫連接,任何與這個連接相關的準備語句必須在調用這個關閉函數之前被釋放掉。
備註8:sqlite3_bind_text()
第1個參數:指向在sqlite3_prepare_v2()調用中使用的sqlite3_stme。
第2個參數:所綁定的變量的索引(sql語句中第一個問號的索引),需要注意的是:第一個問號的索引是1,而不是0。
第3個參數:只有少數綁定函數,比如用於綁定文本或二進制數據的綁定函數,這個參數用來設定傳遞數據的長度。對於C字符串,可以傳遞-1來代替字符串的長度,意思是要是要使用整個字符串。
第4個參數:回調函數,一般用於在語句執行後做內存清理相關的工作。可以設置爲NULL。4、數據庫文件的保存位置是: /Users/duobianxing/Library/Application Support/iPhone Simulator/5.0/Applications/CC47C118-7FE7-4718-A4AA-635FBCC36AED/Documents/data.db3