iOS 資料持久化 CoreData
CoreData是iOS3.0後引入的資料持久化解決方案, 是一種物件關係對映(ORM), 例如java後臺中的Hibernate, iOS中ORM框架首先CoreData, 這是官方推薦的 不需要藉助第三方框架,實際上是對sqlite的封裝,提供了更高階的持久化方式, 在資料庫操作時, 不需要使用sql語句, 也可以直接操作資料庫
ORM框架的作用:將關係資料庫中的表(實體)轉換成程式中的物件, 其本質還是對資料庫的操作, CoreData將物件關係的對映簡化了
使用CoreData進行資料庫存取並不需要手動建立資料庫, 這個過程完全有CoreData框架完成, 開發人員面對的是模型, 主要的工作就是把模型建立起來, 具體的資料庫如何建立也不用管,
CoreData與SQLite相比較, SQLite比較原始, 操作比較複雜, 使用的是C的函式對資料庫進行的操作, 但是CoreData不能跨平臺, SQLite能夠跨平臺, 可控性更強, 更加輕量級.
下面簡單的學習下CoreData的使用:
1. 建立工程的時候要勾選 user CoreData
2. 在Appdelegate中會自動生成以下物件和方法
其中 各個物件的作用:(NSManagerObjectContext 比較重要)
- Persistent Object Store:可以理解為儲存持久物件的資料庫(例如SQLite,注意Core Data也支援其他型別的資料儲存,例如xml、二進位制資料等)。
- Managed Object Model:物件模型,對應Xcode中建立的模型檔案。
- Persistent Store Coordinator:物件模型和實體類之間的轉換協調器,用於管理不同儲存物件的上下文。
- Managed Object Context:物件管理上下文,負責實體物件和資料庫之間的互動。
3. 建立實體模型和關係:
模型建立的過程中注意:
- 實體物件不需要建立ID主鍵,Attributes中應該是有意義屬性(建立過程中應該考慮物件的屬性而不是資料庫中表有幾個欄位,儘管多數屬性會對應表的欄位)。
- 所有的屬性應該指定具體型別(儘管在SQLite中可以不指定),因為實體物件會對應生成ObjC模型類。
- 實體物件中其他實體物件型別的屬性應該通過Relationships建立,並且注意實體之間的對應關係(例如一個使用者有多條微博,而一條微博則只屬於一個使用者,使用者和微博形成一對多的關係)。
4. 根據上面的模型檔案(.xcdatamodeld檔案)生成具體的實體類.
每個實體類系統自動生成了4個檔案User.h, User.m (User的CoreDataProperties的類目)
需要注意的是以下幾點:
- 所有的實體型別都繼承於NSManagedObject,每個NSManagedObject物件對應著資料庫中一條記錄。
- 集合屬性(例如User中的status)生成了訪問此屬性的分類方法。
- 使用@dynamic代表具體屬性實現,具體實現細節不需要開發人員關心。
5. 建立好實體和關係, 就可以對資料進行增刪改查的操作了:
CoreData的增刪改查的操作主要是基於NSManagerObjectContext, 建立上下文, 儲存資料
這裡可以使用Appdelegate提供的NSManagerObjectContext這個物件
增加資料: 需要呼叫NSEntityDescription返回一個實體物件, 然後設定物件的屬性, 儲存上下文(進行增刪改操作的時候, 一定要呼叫管理上下文的儲存方法, 否則操作不會執行)
<span style="font-size:18px;">// 新增資料 - (IBAction)add:(id)sender { // 用NSEntityDescription建立實體物件 User *user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.managerObjectContext]; user.name = @"Xia"; user.age = @"18"; user.time = [NSDate dateWithTimeIntervalSinceNow:0]; NSError *error; // 儲存上下文 if (![self.managerObjectContext save:&error]) { NSLog(@"新增過程中的錯誤資訊---%@", error.localizedDescription); } }</span>
查詢資料: 通過謂詞來實現的, 首先建立一個請求, 設定請求的謂詞, 呼叫上下文執行
注意: 下面有關於NSPredicate拓展
<span style="font-size:18px;">// 查詢資料 - (IBAction)equery:(id)sender { // 查詢獲取請求, 設定查詢哪個實體 EntityName NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"]; // NSFetchRequest 有個屬性 謂詞 predicate(NSPredicate型別) // 類似於查詢語句的查詢條件 用來條件查詢 // 查詢 user表中 name是Xia的User request.predicate = [NSPredicate predicateWithFormat:@"name='Xia'"]; // 也可以使用下面的查詢語句格式 // NSString *name = @"Xia"; // request.predicate = [NSPredicate predicateWithFormat:@"name like [cd] %@", name]; NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil]; }</span>
刪除資料
<span style="font-size:18px;">// 刪除資料 - (IBAction)delete:(id)sender { // 先獲取表裡的所有資料 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"]; NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil]; // 對錶裡資料的陣列進行遍歷 for (User *user in array) { // 條件刪除 if ([user.name isEqualToString:@"Xia"]) { [self.managerObjectContext deleteObject:user]; } } NSError *error; // 儲存上下文 if (![self.managerObjectContext save:&error]) { NSLog(@"刪除過程中發生的錯誤資訊 ----- %@", error.localizedDescription); } }</span>
更新資料
<span style="font-size:18px;">// 更新資料 - (IBAction)update:(id)sender { // 先獲取某個實體 User *user = [self getUserByUserName:@"Xia"]; // 修改實體的屬性 user.name = @"Yan"; user.age = @"20"; NSError *error; // 儲存上下文 if (![self.managerObjectContext save:&error]) { NSLog(@"更新資料發生錯誤 錯誤資訊----%@", error.localizedDescription); } } // 通過username 獲取 User實體類 - (User *)getUserByUserName:(NSString *)username { // User *user = [[User alloc] init]; NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"]; NSArray *array = [self.managerObjectContext executeFetchRequest:request error:nil]; for (User *auser in array) { if ([auser.name isEqualToString:username]) { return auser; } } return nil; }</span>
關於NSPreidicate的拓展
NSPredicate用於查詢和過濾
在SQL中作為查詢條件通常用WHERE,但在COREDATA中作為查詢條件就可以用到NSPredicate.
NSPredicate 不單可以和COREDATA中的FetchRequest 配合使用。也可以與NSArray配合使用。
NSPredicate 中支援的關鍵詞和條件符:
1、>,<,>=,<=,= 比較運算子。
如:
NSPredicate * qcondition= [NSPredicate predicateWithFormat:@"salary >= 10000"];
2、字串操作(包含):BEGINSWITH、ENDSWITH、CONTAINS
如:
@"employee.name BEGINSWITH[cd] '李'" //姓李的員工
@"employee.name ENDSWITH[c] '夢'" //以夢結束的員工
@"employee.name CONTAINS[d] '宗'" //包含有"宗"字的員工
注:[c]不區分大小寫[d]不區分發音符號即沒有重音符號[cd]既不區分大小寫,也不區分發音符號。
3、範圍:IN ,BWTEEN
如:
@"salary BWTEEN {5000,10000}"
@"em_dept IN '開發'"
4、自身:SELF,這個只針對字元陣列起作用。
如:
NSArray * test = =[NSArray arrayWithObjects: @"guangzhou", @"beijing", @"shanghai", nil];
@"SELF='beijing'"
5、萬用字元:LIKE
LIKE 使用?表示一個字元,*表示多個字元,也可以與c、d 連用。
如:
@"car.name LIKE '?he?'" //四個字元中,中間為he
@"car.name LIKE '*jp'" //以jp結束
6、正則表示式:MATCHES
如:
NSString *regex = @"^E.+e$";//以E 開頭,以e 結尾的字元。
NSPredicate *pre= [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
if([pre evaluateWithObject: @"Employee"]){
NSLog(@"matches YES");
}else{
NSLog(@"matches NO");
}
7、邏輯運算子:AND、OR、NOT
如:
@"employee.name = 'john' AND employee.age = 28"
8、佔位符:
NSPredicate *preTemplate = [NSPredicate predicateWithFormat:@"name==$NAME"];
NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:
@"Name1", @"NAME",nil];
NSPredicate *pre=[preTemplate predicateWithSubstitutionVariables: dic];
佔位符就是字典物件裡的key,因此你可以有多個佔位符,只要key 不一樣就可以了。
CoreData的操作會轉換為SQL操作, 在Xcode上設定支援CoreData除錯
Product-Scheme-Edit Scheme-Run-Arguments中依次新增兩個引數(注意引數順序不能錯):-com.apple.CoreData.SQLDebug、1。然後在執行程式過程中如果操作了資料庫就會將SQL語句列印在輸出面板
。
最後注意:CoreData執行緒安全問題 和CoreData的版本遷移問題, 下次有時間再整理