標籤:des blog http io ar os 使用 sp for
9.1 資料持久化概述
9.2 iOS應用程式目錄結構
9.3 讀寫屬性列表
9.4 對象歸檔
9.5 訪問SQLite
9.1 資料持久化概述
iOS中可以有四種持久化資料的方式: 屬性列表、對象歸檔、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存放應用程式的資料。
Library目錄下面還有Preferences和Caches目錄,Preferences目錄存放應用程式的使用偏好,Caches目錄與Documents很相 似可以存放應用程式的資料。
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目錄容易的多。使用函數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
對象歸檔
“歸檔”是值另一種形式的序列化,對模型對象進行歸檔的技術可以輕鬆將複雜的對象寫入檔案,然後再從中讀取它們,只要在類中實現的每個屬性都是基礎資料型別 (Elementary Data Type)(如int或float)或都是符合NSCoding協議的某個類的執行個體,你就可以對你的對象進行完整歸檔。
實現NSCoding協議
NSCoding協議聲明了兩個方法: -(void)encodeWithCoder:(NSCoder *)aCoder,是將對象寫入到檔案中。
-(id)initWithCoder:(NSCoder *)aDecoder,是將檔案中資料讀入到對象中。
實現NSCopying協議
NSCopying協議聲明了一個方法: -(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];用於包含編碼的資料。
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];建立NSKeyedArchiver執行個體,用於將對象歸檔到此theData執行個體中。
[archiver encodeObject:student forKey:@"mystudent"]; 使用“鍵-值”對編碼來對希望包含在歸檔中的對象進行歸檔。
[theData writeToFile:filename atomically:YES]; 寫入資料到歸檔檔案。
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];
建立一個NSKeyedUnarchiver執行個體對資料進行解碼。Student *student = [archiver decodeObjectForKey:@"mystudent"];
使用與歸檔編碼使用相同的鍵對象進行解碼。
9.5 訪問SQLite
SQLite資料庫
SQLite是一個開源的嵌入式關聯式資料庫,它在2000年由D. Richard Hipp發布,它的減少應用程式管理資料的開銷,SQLite可移植性好,很容易使用,很小,高效而且可靠。
SQLite嵌入到使用它的應用程式中,它們共用相同的進程空間,而不是單獨的一個進程。從外部看,它並不像一個RDBMS,但在進程內部,它卻是完整的,自自主資料庫引擎。 嵌入式資料庫的一大好處就是在你的程式內部不需要網路設定,也不需要管理。因為用戶端和伺服器在同一進程空間運行。SQLite 的資料庫許可權只依賴於檔案系統,沒有使用者帳戶的概念。SQLite 有資料庫級鎖定,沒有網路伺服器。它需要的記憶體,其它開銷很小,適合用於嵌入式裝置。你需要做的僅僅是把它正確的編譯到你的程式。
SQLite資料類型
SQLite是無類型的,這意味著你可以儲存任何類型的資料到你所想要儲存的任何錶的任何列中, 無
論這列聲明的資料類型是什麼,對於SQLite來說對欄位不指定類型是完全有效,如:
Create Table ex1(a, b, c);
SQLite允許忽略資料類型,但是仍然建議在你的Create Table語句中指定資料類型, 因為資料類型對於你和其他的程式員交流, 或者你準備換掉你的資料庫引擎。 SQLite支援常見的資料類型, 如:
在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;}
無參數SQLite3處理過程
1、開啟資料庫sqlite3_open。
2、建立資料庫表和執行SQL語句sqlite3_exec。
3、釋放資源sqlite3_close。
建立資料庫
- (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);",
TABLE_NAME, FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS]; if (sqlite3_exec(db, [createSQL UTF8String], NULL, NULL, &error)) { sqlite3_close(db); NSAssert1(NO, @"CREATE TABLE ERROR", error); } else { sqlite3_close(db); } }}
sqlite3_open([[self dataFilePath] UTF8String], &db) != SQLITE_OK sqlite3_open開啟資料庫,注意:在sqlite3中的函數都是使用C字串[self dataFilePath] UTF8String]是將NSString字串轉換為C字串,&db是sqlite3指標(* db)的地址。
該函數sqlite3_open返回SQLITE_OK開啟成功。
sqlite3_exec(db, [tablesql UTF8String], NULL, NULL, &err) != SQLITE_OK
sqlite3_exec是執行任何不帶傳回值sql語句,第2個參數是要執行的sql語句,第3個參數是要回呼函數,第4個參數是要回呼函數的參數,第5個參數是執行出錯的字串。
sqlite3_close(db); 是關閉資料庫。
NSAssert是斷言函數,當宣告失敗時候列印資訊。
NSAssert1是帶有一個參數的NSAssert函數,此外還有NSAssert2等函數。
有參數的SQLite3處理過程
1、開啟資料庫sqlite3_open。
2、預先處理SQL語句sqlite3_prepare_v2。
3、綁定參數sqlite3_bind_text。
4、執行語句sqlite3_step(statement) 。
5、釋放資源sqlite3_finalize?sqlite3_close。
資料儲存
- (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) { //綁定參數開始 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); //執行插入 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執行sql語句,第3個參數-1代表全部sql字串長度,第4個參數&statement是sqlite3_stmt指標(* statement)的地址,第5個參數是sql語句沒有被執行的部分語句。
sqlite3_bind_text(statement, 1, [studentId.text UTF8String], -1, NULL);
是綁定參數,第2個參數為序號(從1開始),第3個參數為字串值,第4個參數為字串長度。 第5個參數為一個函數指標,SQLITE3執行完操作後回調此函數,通常用於釋放字串佔用的記憶體。
sqlite3_step(statement) != SQLITE_DONE判斷是否執行完成sql語句執行。
sqlite3_finalize(statement)和sqlite3_close(db)釋放資源。
查詢資料
- (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) { //綁定參數開始 sqlite3_bind_text(statement, 1, "1000", -1, NULL); //執行 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逐步執行並判斷sql語句執行的狀態。
char *field1 = (char *) sqlite3_column_text(statement, 0); sqlite3_column_text(statement, 0);取出欄位值,第2個參數是列的順序,序號是從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];}
IOS資料持久化的4種方式