1. 程式人生 > >iOS 資料持久化 CoreData

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.SQLDebug1。然後在執行程式過程中如果操作了資料庫就會將SQL語句列印在輸出面板

最後注意:CoreData執行緒安全問題 和CoreData的版本遷移問題, 下次有時間再整理