iOS中的數(shù)據(jù)存儲(chǔ)(下)

摘要

本文介紹iOS中常用的應(yīng)用數(shù)據(jù)存儲(chǔ)方式及其詳細(xì)用法;本章介紹: SQLite3 和 Core Data.

iOS中的數(shù)據(jù)存儲(chǔ)(下)

SQLite3

  • SQLite3是一款開源的嵌入式關(guān)系型數(shù)據(jù)庫,可移植性好,易使用,內(nèi)存開銷小.
  • SQLite3是無類型的,意味著你可以保存任何類型的數(shù)據(jù)到任意表的任意字段中.
  • SQLite3常用的4種數(shù)據(jù)類型:text(文本字符串), integer(整型值), real(浮點(diǎn)值), blob(二進(jìn)制數(shù)據(jù)(比如文件)).
    在iOS中使用SQLite3,首先要添加庫文件'libsqlite3.dylib'和導(dǎo)入主頭文件#import<sqlite3.h>
SQL語句的特點(diǎn):
1> 不區(qū)分大小寫;
2> 每條語句都必須以分號(hào)**;**結(jié)尾
SQL中常用的關(guān)鍵字:
pselect、insert曲饱、update胜臊、delete冠绢、from延届、create龄减、where、desc渣淳、order、by鳄橘、group暗挑、table贝奇、alter该镣、view、index等等
數(shù)據(jù)庫中不可以使用關(guān)鍵字來命名表,字段.
SQL語句種類:
1> 數(shù)據(jù)定義語句(DDL:Data Definition Language) 
包括create和drop等操作 ;
在數(shù)據(jù)庫中創(chuàng)建新表或刪除表(create table或 drop table).
2> 數(shù)據(jù)操作語句(DML:Data Manipulation Language) 
包括insert厂僧、update、delete等操作 ;
上面的3種操作分別用于添加、修改、刪除表中的數(shù)據(jù) .
3> 數(shù)據(jù)查詢語句(DQL:Data Query Language)
可以用于查詢獲得表中的數(shù)據(jù) ;
關(guān)鍵字select是DQL(也是所有SQL)用得最多的操作 ;
其他DQL常用的關(guān)鍵字有where呆瞻,order by前域,group by和having創(chuàng)建.
創(chuàng)表:

create table if not exists t_student (id integer, name text, age inetger, score real) ;

刪表:
``drop table if exists t_student;``
插入數(shù)據(jù)(insert):
``insert into t_student (name, age) values ('JN', 22) ;``
注意:數(shù)據(jù)庫中的字符串內(nèi)容應(yīng)該用單引號(hào)''括住.
更新數(shù)據(jù)(updata):
``pupdate t_student set name = 'jack', age = 20 ; ``    
注意:上面的更新會(huì)將t_student表中所有記錄的name都改為jack,age都改為20;
刪除數(shù)據(jù)(delete):
``delete from t_student;``
會(huì)將t_student表中所有記錄都刪掉.
如果只想更新或者刪除某些固定的記錄,那就必須在DML語句后加上一些條件.示例如下:
  // 將t_student表中年齡大于10 并且 姓名不等于jack的記錄,年齡都改為 5  
  update t_student set age = 5 where age > 10 and name != ‘jack’ ;  
  // 刪除t_student表中年齡小于等于10 或者 年齡大于30的記錄  
  delete from t_student where age <= 10 or age > 30 ;
查詢語句(DQL):
select * from t_student where age > 10 ;  //  條件查詢條件語句:
主鍵約束:
每張表都必須有一個(gè)主鍵,用來標(biāo)識(shí)記錄的唯一性.

什么是主鍵:
主鍵(Primary Key,簡(jiǎn)稱PK),用來唯一的標(biāo)識(shí)某一條記錄.
例如t_student可以增加一個(gè)id字段作為主鍵,相當(dāng)于人的身份證.
主鍵可以是一個(gè)字段或多個(gè)字段.

外鍵約束:
利用外鍵約束可以來建立表與表之間的聯(lián)系.
外鍵的一般情況是:一張表的某個(gè)字段引用著另一張表的主鍵字段.
打開,關(guān)閉數(shù)據(jù)庫
創(chuàng)建或打開數(shù)據(jù)庫:
  // path為:~/Documents/person.db
  sqlite3 *db;int result = sqlite3_open([path UTF8String], &db);

代碼解析:
sqlite3_open()將根據(jù)文件路徑打開數(shù)據(jù)庫,如果不存在,則會(huì)創(chuàng)建一個(gè)新的數(shù)據(jù)庫.如果result等于常量SQLITE_OK,則表示成功打開數(shù)據(jù)庫.
sqlite *db:一個(gè)打開的數(shù)據(jù)庫實(shí)例.
數(shù)據(jù)庫文件的路徑必須以C字符串(而非NSString)傳入.
關(guān)閉數(shù)據(jù)庫:sqlite3_close(db);
執(zhí)行不返回語句的SQL語句
char *errorMsg; // 用來存儲(chǔ)錯(cuò)誤信息
char *sql = "create table if not exists t_person(id integer primary key autoincrement, name text, age integer);";
int result = sqlite3_exec(db, sql, NULL, NULL, &errorMsg);

代碼解析:
sqlite3_exec()可以執(zhí)行任何SQL語句,比如創(chuàng)表, 更新, 插入和刪除操作.但是一般不用它執(zhí)行查詢語句,因?yàn)樗粫?huì)返回查詢到得數(shù)據(jù).
sqlite3_exec()還可以執(zhí)行的語句:
1> 開啟事務(wù):begain transaction;
2> 回滾事務(wù):rollback
3> 提交事務(wù):commit

SQLite函數(shù)總結(jié):
  1.打開數(shù)據(jù)庫
  int sqlite3_open(    
  const char *filename,   // 數(shù)據(jù)庫的文件路徑    
  sqlite3 **ppDb          // 數(shù)據(jù)庫實(shí)例
  );
  2.執(zhí)行任何SQL語句
  int sqlite3_exec(    
  sqlite3*,               // 一個(gè)打開的數(shù)據(jù)庫實(shí)例    
  const char *sql,                           // 需要執(zhí)行的SQL語句    
  int (*callback)(void*,int,char**,char**),  // SQL語句執(zhí)行完畢后的回調(diào)    
  void *,                                    // 回調(diào)函數(shù)的第1個(gè)參數(shù)    
  char **errmsg                              // 錯(cuò)誤信息
  );
  3.檢查SQL語句的合法性(查詢前的準(zhǔn)備)
  int sqlite3_prepare_v2(
      sqlite3 *db,            // 數(shù)據(jù)庫實(shí)例    
  const char *zSql,       // 需要檢查的SQL語句    
  int nByte,              // SQL語句的最大字節(jié)長度    
  sqlite3_stmt **ppStmt,  // sqlite3_stmt實(shí)例给梅,用來獲得數(shù)據(jù)庫數(shù)據(jù)    
  const char **pzTail
  );
  4.查詢一行數(shù)據(jù)
  int sqlite3_step(
  sqlite3_stmt*); // 如果查詢到一行數(shù)據(jù),就會(huì)返回SQLITE_ROW
  5.利用stmt獲得某一字段的值(字段的下標(biāo)從0開始)
  double sqlite3_column_double(sqlite3_stmt*, int iCol);  // 浮點(diǎn)數(shù)據(jù)
  int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型數(shù)據(jù)
  sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 長整型數(shù)據(jù)
  const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二進(jìn)制文本數(shù)據(jù)
  const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);  // 字符串?dāng)?shù)據(jù)

CoreData

Core Data框架提供了對(duì)象-關(guān)系映射(ORM)的功能,即能夠?qū)C對(duì)象轉(zhuǎn)化成數(shù)據(jù),保存在SQLite3數(shù)據(jù)庫文件中,也能將保存在數(shù)據(jù)庫中的數(shù)據(jù)還原成OC對(duì)象.在次數(shù)據(jù)操作期間,不需要編寫任何SQL語句.

使用此功能,要添加CoreData.framework和導(dǎo)入主頭文件<CoreDate/CoreData.h>.

模型文件:在CoreData中,需要進(jìn)行映射的對(duì)象稱為實(shí)體(entity),而且需要使用CoreData的模型文件來描述應(yīng)用的所有實(shí)體和實(shí)體屬性.

NSManagedObject

通過Core Data從數(shù)據(jù)庫中取出的對(duì)象,默認(rèn)情況下都是NSManagedObject對(duì)象. NSManagedObject的工作模式有點(diǎn)類似于NSDictionary對(duì)象,通過鍵-值對(duì)來存取所有的實(shí)體屬性. setValue:forkey:存儲(chǔ)屬性值(屬性名為key); valueForKey:獲取屬性值(屬性名為key).

CoreData主要對(duì)象

NSManagedObjectContext:負(fù)責(zé)數(shù)據(jù)和應(yīng)用庫之間的交互(CRUD); NSPersistentStoreCoordinator:添加持久化存儲(chǔ)庫(比如SQLite數(shù)據(jù)庫); NSManagedObjectModel:代表Core Data的模型文件; NSEntityDescription:用來描述實(shí)體;

搭建CoreData上下文環(huán)境:
// 從應(yīng)用程序包中加載模型文件 
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
// 傳入模型双揪,初始化
NSPersistentStoreCoordinator NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// 構(gòu)建SQLite文件路徑 
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)  lastObject];NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@"person.data"]];
// 添加持久化存儲(chǔ)庫动羽,這里使用SQLite作為存儲(chǔ)庫 
NSError *error = nil;
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
if (store == nil) { // 直接拋異常    
       [NSException raise:@"添加數(shù)據(jù)庫錯(cuò)誤" format:@"%@", [error localizedDescription]];
}
// 初始化上下文,設(shè)置persistentStoreCoordinator屬性 
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];context.persistentStoreCoordinator = psc;
// 用完之后渔期,還是要[context release];
/*持久化存儲(chǔ)庫的類型:NSSQLiteStoreType  SQLite數(shù)據(jù)庫 
NSBinaryStoreType  二進(jìn)制平面文件 
NSInMemoryStoreType 內(nèi)存庫运吓,無法永久保存數(shù)據(jù) 
雖然這3種類型的性能從速度上來說都差不多,但從數(shù)據(jù)模型中保留下來的信息卻不一樣
在幾乎所有的情景中疯趟,都應(yīng)該采用默認(rèn)設(shè)置拘哨,使用SQLite作為持久化存儲(chǔ)庫
*/
添加數(shù)據(jù):
// 傳入上下文,創(chuàng)建一個(gè)Person實(shí)體對(duì)象 
NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
// 設(shè)置簡(jiǎn)單屬性 
[person setValue:@"JN" forKey:@"name"];
[person setValue:[NSNumber numberWithInt:22] forKey:@"age"];
// 傳入上下文信峻,創(chuàng)建一個(gè)Card實(shí)體對(duì)象 
NSManagedObject *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context];
[card setValue:@"447640819" forKey:@"no"];
// 設(shè)置Person和Card之間的關(guān)聯(lián)關(guān)系 
[person setValue:card forKey:@"card"];
 // 利用上下文對(duì)象倦青,將數(shù)據(jù)同步到持久化存儲(chǔ)庫 
NSError *error = nil;BOOL success = [context save:&error];
if (!success) { 
       [NSException raise:@"訪問數(shù)據(jù)庫錯(cuò)誤" format:@"%@", [error localizedDescription]];
}
// 如果是想做更新操作:只要在更改了實(shí)體對(duì)象的屬性后調(diào)用[context save:&error],就能將更改的數(shù)據(jù)同步到數(shù)據(jù)庫
查詢數(shù)據(jù):
// 初始化一個(gè)查詢請(qǐng)求 
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 設(shè)置要查詢的實(shí)體 
NSEntityDescription *desc = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
// 設(shè)置排序(按照age降序) 
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];
// 設(shè)置條件過濾(name like '%JN-1%') 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*JN-1*"];
request.predicate = predicate;
注意:設(shè)置條件過濾時(shí)盹舞,數(shù)據(jù)庫里面的%要用*來代替
// 執(zhí)行請(qǐng)求 
NSError *error = nil;
NSArray *objs = [context executeFetchRequest:request error:&error];
if (error) {
      [NSException raise:@"查詢錯(cuò)誤" format:@"%@", [error localizedDescription]];
}
// 遍歷數(shù)據(jù) 
for (NSManagedObject *obj in objs) {
      NSLog(@"name=%@", [obj valueForKey:@"name"]
}
刪除數(shù)據(jù):
// 傳入需要?jiǎng)h除的實(shí)體對(duì)象
 [context deleteObject:managedObject];
// 將結(jié)果同步到數(shù)據(jù)庫NSError *error = nil;
 [context save:&error];
if (error) { 
    [NSException raise:@"刪除錯(cuò)誤" format:@"%@",[error localizedDescription]];
}
Core Data的延遲加載:
Core Data不會(huì)根據(jù)實(shí)體中的關(guān)聯(lián)關(guān)系立即獲取相應(yīng)的關(guān)聯(lián)對(duì)象;比如通過Core Data取出Person實(shí)體時(shí),并不會(huì)立即查詢相關(guān)聯(lián)的Card實(shí)體,當(dāng)應(yīng)用真的需要使用Card時(shí),才會(huì)查詢數(shù)據(jù)庫,加載Card實(shí)體信息.

創(chuàng)建NSManagedObject的子類:

默認(rèn)情況下,利用Core Data取出的實(shí)體都是NSManagedObject類型的,能夠利用鍵-值對(duì)來存取數(shù)據(jù).

但是一般情況下,實(shí)體在存取數(shù)據(jù)的基礎(chǔ)上,有時(shí)還需要添加一些業(yè)務(wù)方法來完成一些其他任務(wù),那么就必須創(chuàng)建NSManagedObject的子類.

// 那么生成一個(gè)Person實(shí)體對(duì)象就應(yīng)該這樣寫 
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
person.name = @"JN";person.age = [NSNumber numberWithInt:24];
Card *card = [NSEntityDescription insertNewObjectForEntityForName:@”Card" inManagedObjectContext:context];
card.no = @”447640819";
person.card = card;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姨夹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子矾策,更是在濱河造成了極大的恐慌磷账,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贾虽,死亡現(xiàn)場(chǎng)離奇詭異逃糟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蓬豁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門绰咽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人地粪,你說我怎么就攤上這事取募。” “怎么了蟆技?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵玩敏,是天一觀的道長斗忌。 經(jīng)常有香客問我,道長旺聚,這世上最難降的妖魔是什么织阳? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮砰粹,結(jié)果婚禮上唧躲,老公的妹妹穿的比我還像新娘。我一直安慰自己碱璃,他們只是感情好弄痹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嵌器,像睡著了一般肛真。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘴秸,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天毁欣,我揣著相機(jī)與錄音,去河邊找鬼岳掐。 笑死凭疮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的串述。 我是一名探鬼主播执解,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼纲酗!你這毒婦竟也來了衰腌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤觅赊,失蹤者是張志新(化名)和其女友劉穎右蕊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吮螺,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饶囚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠补。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萝风。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖紫岩,靈堂內(nèi)的尸體忽然破棺而出规惰,到底是詐尸還是另有隱情,我是刑警寧澤泉蝌,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布歇万,位于F島的核電站揩晴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏堕花。R本人自食惡果不足惜文狱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一粥鞋、第九天 我趴在偏房一處隱蔽的房頂上張望缘挽。 院中可真熱鬧,春花似錦呻粹、人聲如沸壕曼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腮郊。三九已至,卻和暖如春筹燕,著一層夾襖步出監(jiān)牢的瞬間轧飞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工撒踪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留过咬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓制妄,卻偏偏與公主長得像掸绞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耕捞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容