9.1 數(shù)據(jù)持久化概述iOS中可以有四種持久化數(shù)據(jù)的方式: 屬性列表,、對象歸檔,、SQLite3和Core Data 9.2 iOS應用程序目錄結構iOS應用程序運行在Mac os模擬器時候,有一下臨時目錄模擬器3.1.3為例子: /Users/tony/Library/Application Support/iPhone Simulator/3.1.3/Applications IOS應用程序采用沙盒原理設計,,ios每個應用程序都有自己的3個目錄(Document,Library,tmp),,互相之間不能訪問。 Documents存放應用程序的數(shù)據(jù),。 Library目錄下面還有Preferences和Caches目錄,,Preferences目錄存放應用程序的使用偏好,Caches目錄與Documents很相 似可以存放應用程序的數(shù)據(jù),。 tmp目錄供應用程序存儲臨時文件,。 9.3 讀寫屬性列表讀取Documents目錄下文件 可以獲得應用程序的Documents文件夾。 NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* myDocPath = [myPaths objectAtIndex:0]; 獲取文件的完整路徑,。 - (NSString*)filePath:(NSString*)fileName { NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* myDocPath = [myPaths objectAtIndex:0]; NSString* filePath = [myDocPath stringByAppendingPathComponent:fileName]; return filePath; }
獲取tmp目錄 獲取應用程序的tmp目錄要比獲取Documents目錄容易的多,。使用函數(shù)NSTemporaryDirectory ()可以獲得tmp目錄路徑。 NSString* tempPath = NSTemporaryDirectory(); 獲取文件的完整路徑,。 NSString* tempFile = [tempPath stringByAppendingPathComponent:@"properties.plist"];
屬性列表文件實例 :PropertesList PropertesListViewController.h #import "Student.h" @interface ViewController : UIViewController @property (retain, nonatomic) IBOutlet UITextField *studentNo; @property (retain, nonatomic) IBOutlet UITextField *studentName; @property (retain, nonatomic) IBOutlet UITextField *studentClass; - (IBAction)save:(id)sender; - (IBAction)load:(id)sender; - (IBAction)endEditing:(id)sender; - (IBAction)saveToArchiver:(id)sender; - (IBAction)loadFromArchiver:(id)sender; - (NSString*)filePath:(NSString*)fileName; @end
PropertesListViewController.m @synthesize studentNo; @synthesize studentName; @synthesize studentClass; - (NSString*)filePath:(NSString*)fileName { NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* myDocPath = [myPaths objectAtIndex:0]; NSString* filePath = [myDocPath stringByAppendingPathComponent:fileName]; return filePath; } - (IBAction)save:(id)sender { NSString* fileName = [self filePath:@"properties.plist"]; NSLog(fileName); NSMutableArray* data = [[NSMutableArray alloc]init]; [data addObject:studentNo.text]; [data addObject:studentName.text]; [data addObject:studentClass.text]; [data writeToFile:fileName atomically:YES]; } - (IBAction)load:(id)sender { NSString* fileName = [self filePath:@"properties.plist"]; if ([[NSFileManager defaultManager]fileExistsAtPath:fileName]) { NSArray* data = [[NSArray alloc]initWithContentsOfFile:fileName]; studentNo.text = [data objectAtIndex:0]; studentName.text = [data objectAtIndex:1]; studentClass.text = [data objectAtIndex:2]; [data release]; } } - (IBAction)endEditing:(id)sender { [sender resignFirstResponder]; } 9.4 對象歸檔對象歸檔實例:Encoding 對象歸檔 “歸檔”是值另一種形式的序列化,,對模型對象進行歸檔的技術可以輕松將復雜的對象寫入文件,然后再從中讀取它們,,只要在類中實現(xiàn)的每個屬性都是基本數(shù)據(jù)類型(如int或float)或都是符合NSCoding協(xié)議的某個類的實例,,你就可以對你的對象進行完整歸檔。 實現(xiàn)NSCoding協(xié)議 NSCoding協(xié)議聲明了兩個方法: -(void)encodeWithCoder:(NSCoder *)aCoder,,是將對象寫入到文件中,。 -(id)initWithCoder:(NSCoder *)aDecoder,是將文件中數(shù)據(jù)讀入到對象中,。 實現(xiàn)NSCopying協(xié)議 NSCopying協(xié)議聲明了一個方法: -(id)copyWithZone:(NSZone *)zone ,,是將對象復制方法。 Student.h @interface Student : NSObject<NSCoding, NSCopying> @property (retain, nonatomic) NSString* studentNo; @property (retain, nonatomic) NSString* studentName; @property (retain, nonatomic) NSString* studentClass; @end
Student.m #import "Student.h" @implementation Student @synthesize studentNo = _studentNo; @synthesize studentName = _studentName; @synthesize studentClass = _studentClass; #pragma mark NSCopying - (id)copyWithZone:(NSZone *)zone { Student* copy = [[[self class]allocWithZone:zone]init]; copy.studentNo = [_studentNo copyWithZone:zone]; copy.studentName = [_studentName copyWithZone:zone]; copy.studentClass = [_studentClass copyWithZone:zone]; return copy; } #pragma mark NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_studentNo forKey:@"studentNo"]; [aCoder encodeObject:_studentName forKey:@"studentName"]; [aCoder encodeObject:_studentClass forKey:@"studentClass"]; } - (id)initWithCoder:(NSCoder *)aDecoder { _studentNo = [aDecoder decodeObjectForKey:@"studentNo"]; _studentName = [aDecoder decodeObjectForKey:@"studentName"]; _studentClass = [aDecoder decodeObjectForKey:@"studentClass"]; return self; } -(NSString*)description { return [[[NSString alloc]initWithFormat:@"no:%@ name:%@ class:%@", _studentNo, _studentName, _studentClass]autorelease]; } - (void)dealloc { [_studentName release]; [_studentClass release]; [_studentNo release]; [super dealloc]; } @end
EncodingViewController.h 詳細見上,。 EncodingViewController.m - (IBAction)saveToArchiver:(id)sender { NSString* fileName = [self filePath:@"student.archiver"]; NSMutableData* data = [NSMutableData data]; NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data]; Student* student = [[Student alloc]init]; student.studentNo = studentNo.text; student.studentName = studentName.text; student.studentClass = studentClass.text; [archiver encodeObject:student forKey:@"myStudent"]; [archiver finishEncoding]; [data writeToFile:fileName atomically:YES]; [archiver release]; [student release]; } NSMutableData * theData = [NSMutableData data];用于包含編碼的數(shù)據(jù),。 NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];創(chuàng)建NSKeyedArchiver實例,用于將對象歸檔到此theData實例中,。 [archiver encodeObject:student forKey:@"mystudent"]; 使用“鍵-值”對編碼來對希望包含在歸檔中的對象進行歸檔,。 [theData writeToFile:filename atomically:YES]; 寫入數(shù)據(jù)到歸檔文件。 EncodingViewController.m - (IBAction)loadFromArchiver:(id)sender { NSString* fileName = [self filePath:@"student.archiver"]; NSData* data = [NSData dataWithContentsOfFile:fileName]; if ([data length] > 0) { NSKeyedUnarchiver* unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data]; Student* student = [unArchiver decodeObjectForKey:@"myStudent"]; studentNo.text = student.studentNo; studentName.text = student.studentName; studentClass.text = student.studentClass; [unArchiver finishDecoding]; [unArchiver release]; } }
NSData * theData =[NSData dataWithContentsOfFile:filename];從歸檔文件中獲得NSData實例,。 NSKeyedUnarchiver * archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData]; 創(chuàng)建一個NSKeyedUnarchiver實例對數(shù)據(jù)進行解碼,。Student *student = [archiver decodeObjectForKey:@"mystudent"]; 使用與歸檔編碼使用相同的鍵對象進行解碼。 9.5 訪問SQLiteSQLite數(shù)據(jù)庫 SQLite是一個開源的嵌入式關系數(shù)據(jù)庫,,它在2000年由D. Richard Hipp發(fā)布,,它的減少應用程序管理數(shù)據(jù)的開銷,SQLite可移植性好,,很容易使用,,很小,,高效而且可靠。 SQLite嵌入到使用它的應用程序中,,它們共用相同的進程空間,,而不是單獨的一個進程。從外部看,,它并不像一個RDBMS,,但在進程內部,它卻是完整的,,自包含的數(shù)據(jù)庫引擎,。 嵌入式數(shù)據(jù)庫的一大好處就是在你的程序內部不需要網(wǎng)絡配置,也不需要管理,。因為客戶端和服務器在同一進程空間運行,。SQLite 的數(shù)據(jù)庫權限只依賴于文件系統(tǒng),,沒有用戶帳戶的概念,。SQLite 有數(shù)據(jù)庫級鎖定,沒有網(wǎng)絡服務器,。它需要的內存,,其它開銷很小,適合用于嵌入式設備,。你需要做的僅僅是把它正確的編譯到你的程序,。 SQLite數(shù)據(jù)類型 SQLite是無類型的,這意味著你可以保存任何類型的數(shù)據(jù)到你所想要保存的任何表的任何列中, 無 論這列聲明的數(shù)據(jù)類型是什么,,對于SQLite來說對字段不指定類型是完全有效的,,如: Create Table ex1(a, b, c); SQLite允許忽略數(shù)據(jù)類型,但是仍然建議在你的Create Table語句中指定數(shù)據(jù)類型,, 因為數(shù)據(jù)類型對于你和其他的程序員交流,, 或者你準備換掉你的數(shù)據(jù)庫引擎。 SQLite支持常見的數(shù)據(jù)類型,, 如: 在iOS中使用SQLite3 為了能夠在iOS中使用SQLite3需要是將libsqlite3.dylib類庫添加到Xcode工程中,,在工程的Frameworks(框架) 文件夾右鍵添加存在Frameworks 或者導航到 /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/ iPhoneSimulator<version>.sdk/usr/lib 目錄下面找到libsqlite3.dylib. 實例:StudentSQLite3 StudentSQLite3ViewController.h #import "sqlite3.h" #define DATA_FILE @"data.sqlite3" #define TABLE_NAME @"student" #define FIELDS_NAME_SID @"studentId" #define FIELDS_NAME_SNAME @"studentName" #define FIELDS_NAME_SCLASS @"studentClass" @interface ViewController : UIViewController { sqlite3* db; } @property (retain, nonatomic) IBOutlet UITextField *studentId; @property (retain, nonatomic) IBOutlet UITextField *studentName; @property (retain, nonatomic) IBOutlet UITextField *studentClass; - (IBAction)saveFromSqlite:(id)sender; - (IBAction)loadFromSqlite:(id)sender; -(NSString*)dataFile; -(IBAction)textFieldDoneEditing:(id)sender; @end
StudentSQLite3ViewController.m @synthesize studentId; @synthesize studentName; @synthesize studentClass; -(NSString*)dataFile { NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* myDocPath = [myPaths objectAtIndex:0]; NSString* fileName = [myDocPath stringByAppendingFormat:DATA_FILE]; return fileName; }
無參數(shù)SQLite3處理過程 1、打開數(shù)據(jù)庫sqlite3_open,。 2,、創(chuàng)建數(shù)據(jù)庫表和執(zhí)行SQL語句sqlite3_exec。 3,、釋放資源sqlite3_close,。 創(chuàng)建數(shù)據(jù)庫 - (void)viewDidLoad { [super viewDidLoad]; NSString* fileName = [self dataFile]; NSLog(@"%@", fileName); if (sqlite3_open([fileName UTF8String], &db) != SQLITE_OK) { sqlite3_close(db); NSAssert(NO, @"OPEN SQLITE DATABASE ERROR!"); } else { char* error; NSString* createSQL = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@ TEXT PRIMARY KEY, %@ TEXT, %@% TEXT);",
sqlite3_open([[self dataFilePath] UTF8String], &db) != SQLITE_OK sqlite3_open打開數(shù)據(jù)庫,,注意:在sqlite3中的函數(shù)都是使用C字符串[self dataFilePath] UTF8String]是將NSString字符串轉換為C字符串,,&db是sqlite3指針(* db)的地址,。 該函數(shù)sqlite3_open返回SQLITE_OK打開成功。 sqlite3_exec(db, [tablesql UTF8String], NULL, NULL, &err) != SQLITE_OK sqlite3_exec是執(zhí)行任何不帶返回值sql語句,,第2個參數(shù)是要執(zhí)行的sql語句,,第3個參數(shù)是要回調函數(shù),第4個參數(shù)是要回調函數(shù)的參數(shù),,第5個參數(shù)是執(zhí)行出錯的字符串,。 sqlite3_close(db); 是關閉數(shù)據(jù)庫。 NSAssert是斷言函數(shù),,當斷言失敗時候打印信息,。 NSAssert1是帶有一個參數(shù)的NSAssert函數(shù),此外還有NSAssert2等函數(shù),。 有參數(shù)的SQLite3處理過程 1,、打開數(shù)據(jù)庫sqlite3_open。 2,、預處理SQL語句sqlite3_prepare_v2,。 3、綁定參數(shù)sqlite3_bind_text,。 4,、執(zhí)行語句sqlite3_step(statement) 。 5,、釋放資源sqlite3_finalize?sqlite3_close,。 數(shù)據(jù)保存 - (IBAction)saveFromSqlite:(id)sender { NSString* fileName = [self dataFile]; NSLog(@"%@", fileName); if (sqlite3_open([fileName UTF8String], &db)) { sqlite3_close(db); NSAssert(NO, @"OPEN DATABASE ERROR"); } else { NSString* sqlStr = [NSString stringWithFormat:@"INSERT OR REPLACE INTO %@(%@, %@, %@) VALUES(?, ?, ?)",TABLE_NAME, FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS]; sqlite3_stmt* statement; //預處理過程 if (sqlite3_prepare(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { //綁定參數(shù)開始 sqlite3_bind_text(statement, 1, [studentId.text UTF8String], -1, NULL); sqlite3_bind_text(statement, 2, [studentName.text UTF8String], -1, NULL); sqlite3_bind_text(statement, 3, [studentClass.text UTF8String], -1, NULL); //執(zhí)行插入 if (sqlite3_step(statement) != SQLITE_DONE) { NSAssert(0, @"INSERT DATABASE ERROR!"); } } sqlite3_finalize(statement); sqlite3_close(db); } }
sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, nil) == SQLITE_OK sqlite3_prepare_v2執(zhí)行sql語句,第3個參數(shù)-1代表全部sql字符串長度,,第4個參數(shù)&statement是sqlite3_stmt指針(* statement)的地址,,第5個參數(shù)是sql語句沒有被執(zhí)行的部分語句。 sqlite3_bind_text(statement, 1, [studentId.text UTF8String], -1, NULL); 是綁定參數(shù),,第2個參數(shù)為序號(從1開始),,第3個參數(shù)為字符串值,第4個參數(shù)為字符串長度,。 第5個參數(shù)為一個函數(shù)指針,,SQLITE3執(zhí)行完操作后回調此函數(shù),通常用于釋放字符串占用的內存,。 sqlite3_step(statement) != SQLITE_DONE判斷是否執(zhí)行完成sql語句執(zhí)行,。 sqlite3_finalize(statement)和sqlite3_close(db)釋放資源。 查詢數(shù)據(jù) - (IBAction)loadFromSqlite:(id)sender { NSString* fileName = [self dataFile]; NSLog(@"%@", fileName); if (sqlite3_open([fileName UTF8String], &db) != SQLITE_OK) { sqlite3_close(db); NSAssert(NO, @"OPEN DATABASE ERROR!"); } else { NSString* sqlStr = [NSString stringWithFormat:@"SELECT %@,%@,%@ FROM %@ WHERE %@=?", FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS, TABLE_NAME, FIELDS_NAME_SID]; sqlite3_stmt* statement; //預處理過程 if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { //綁定參數(shù)開始 sqlite3_bind_text(statement, 1, "1000", -1, NULL); //執(zhí)行 while (sqlite3_step(statement) == SQLITE_ROW) { char* field1 = (char*)sqlite3_column_text(statement, 0); NSString* field1Str = [[NSString alloc]initWithUTF8String:field1]; studentId.text = field1Str; char* field2 = (char*)sqlite3_column_text(statement, 1); NSString* field2Str = [[NSString alloc]initWithUTF8String:field2]; studentName.text = field2Str; char* field3 = (char*)sqlite3_column_text(statement, 2); NSString* field3Str = [[NSString alloc]initWithUTF8String:field3]; studentClass.text = field3Str; [field1Str release]; [field2Str release]; [field3Str release]; } } sqlite3_finalize(statement); sqlite3_close(db); } }
while (sqlite3_step(statement) == SQLITE_ROW) sqlite3_step(statement) == SQLITE_ROW單步執(zhí)行并判斷sql語句執(zhí)行的狀態(tài),。 char *field1 = (char *) sqlite3_column_text(statement, 0); sqlite3_column_text(statement, 0);取出字段值,,第2個參數(shù)是列的順序,序號是從0開始,。 NSString *field1Str = [[NSString alloc] initWithUTF8String: field1];構建NSSting字符串,。 其它部分代碼 -(IBAction)textFieldDoneEditing:(id)sender { [sender resignFirstResponder]; } - (void)viewDidUnload { [self setStudentId:nil]; [self setStudentName:nil]; [self setStudentClass:nil]; [super viewDidUnload]; } - (void)dealloc { [studentId release]; [studentName release]; [studentClass release]; [super dealloc]; }
|
|
來自: 螢火與皓月 > 《數(shù)據(jù)庫》