CoreData:使用CoreData完成一個通訊錄儲存

非典型技術宅發表於2018-03-14

CoreData作為Apple的親兒子,依然在App需要儲存結構化資料上發揮著重要的作用。CoreData已經超過十年了,而且親爹還在積極的維護著它。

在Monster、Indeed這些海外主流招聘網站看一下iOS的職位,基本上都會大大寫著要求會熟練使用CoreData。

然而這麼一個成熟,被實踐檢驗過的程式碼庫反而在國內使用並不是特別多。FMDB、Realm等等在被廣泛使用。經常在面試的時候問iOSer是不是瞭解資料庫,回答都是瞭解。再一細問,很多人也都是隻使用到了FMDB,對於CoreData卻是瞭解甚少。

後來想了想,可能是因為CoreData的入門成本有點高,而且相關的中文資料比較少的緣故吧。

為了寫這個系列,還專門買來了objc.io的CoreData這本書。讀完之後受益匪淺。

這個系列要寫多少篇還沒有想好,大概也還是會從基本到高階的一個過渡。

第一篇通過一個通訊錄實現資料庫的讀取。第二篇會儲存更多型別的資料。

最終實現結果:

CoreDataDemo.gif

1. Core Data架構

一個基本的 Core Data 棧由四個主要部分組成:託管物件 (NSManagedObject),託管物件上下文 (NSManagedObjectContext),持久化儲存協調器 (NSPersistentStoreCoordinator),以及持久化儲存 (NSPersistentStore)。

image.png

  • NSManagedObject是我們的資料模型,也就是我們儲存的物件。這些物件都儲存在NSManagedObjectContext中,每個儲存物件都知道自己對應哪個上下文。

  • NSManagedObjectContext :日常打交道的都是這個。其他三個在資料遷移的時候才會看到。

  • NSPersistenStoreCoordinator : 是模型和儲存資料庫之間的橋樑,負責兩者之間最複雜的細節隱藏。

關於Context想多說點,因為是天天都打交道的嘛。它其實是記憶體中的一塊區域,物件所有的操作都需要一個context。直到save之前,都是在記憶體中,不會對資料庫中的內容有任何影響。每一個託管物件都對應一個Context,一個物件只會跟一個特定的Context打交道。直到生命週期結束。

Context是執行緒不安全的。

2. CoreData的基本讀取操作

2. 1 獲取CoreData已經儲存資料的五個步驟

  1. 獲取總代理和託管物件總管
  2. 從Entity獲取一個fetchRequest
  3. 根據fetchRequest,從managedContext中查詢資料
  4. 儲存。儲存過程中可能會出錯,要做一下處理。
  5. 新增到陣列中

2.2 基本儲存

  1. 獲取總代理和託管物件總管
  2. 建立一個Entity
  3. 儲存內容
  4. 儲存Entity到託管物件。如果儲存失敗,進行處理
  5. 儲存到陣列中,更新UI

3. 更新一個通訊錄的列表頁Demo

需求:完成一個通訊錄的列表頁。要求:

  1. 從本地資料庫中讀取名字列表
  2. 點選增加可以新增一個名字
  3. 新增的名字可以儲存到本地資料庫中

好,接下來我們們來一步一步實現這個需求。為了突出重點,我們們先從最簡單的開始,使用預設帶資料庫的工程進行著手。

3.1 Xcode建立預設帶資料庫的工程

image.png

在 Xcode 建立工程時,提供了建立 CoreData 的模板,只需要我們在建立時,勾選 CoreData 選項,Xcode 就會自動建立出資料模型檔案。

這個Demo用這個建立,純粹是為了簡單直奔主題。不然還要一開始分享很多其他的內容,看官們會覺得膩的。

但是,實際開發中不建議使用這種方式建立。通常情況下我們都會把生成的模板程式碼都刪除的。

3.2 建立本地資料庫模板

image.png

勾選完成之後,會看到一個字尾名是"xcdatamodeld"的檔案,這個就是我們們的資料庫模板啦。

當然,現在裡面是還不能存資料的,還需要我們設定一下欄位名稱。

image.png
第一步,要新增一個Entity,這個就相當於是資料庫中的一張表。

第二步,對新建的Entity命名。

第三步,設計Entity裡面的屬性。我們們這個Demo的需求裡面只需要一個人名,所以就只設定了一個名字叫做name的屬性,型別是String。

其他更多的屬性型別,我們會在下面一篇文章分享。

3.3 查詢本地資料

咦?在最開始的不是說一個基本的 Core Data 棧由四個主要部分組成嘛?怎麼沒有看到吶?

來來來,這就是最開始我們使用Xcode建立預設帶資料庫的工程的原因。使用了這個選項,會自動的在AppDelegate中生成相應的程式碼。確實簡化了我們們第一次學習的成本,但是就像沒人會把所有程式碼都寫在Controller裡面一樣,在APPDelegate也不會寫這些東西。

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        //        步驟一:獲取總代理和託管物件總管
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        
        let managedObectContext = appDelegate.persistentContainer.viewContext
        
//        步驟二:建立一個獲取的請求
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
        
//        步驟三:執行請求
        do {
            let fetchedResults = try managedObectContext.fetch(fetchRequest) as? [NSManagedObject]
            if let results = fetchedResults {
                people = results
                
                tableView.reloadData()
            }
            
        } catch  {
            fatalError("獲取失敗")
        }
    }
複製程式碼

3.4 插入並儲存資料至本地資料庫

private func saveName(text: String) {
    //        步驟一:獲取總代理和託管物件總管
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    
    let managedObectContext = appDelegate.persistentContainer.viewContext
    
    //        步驟二:建立一個entity
    let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedObectContext)
    
    let person = NSManagedObject(entity: entity!, insertInto: managedObectContext)
    
    //        步驟三:儲存文字框中的值到person
    person.setValue(text, forKey: "name")
    
    //        步驟四:儲存entity到託管物件中。如果儲存失敗,進行處理
    do {
        try managedObectContext.save()
    } catch  {
        fatalError("無法儲存")
    }
    
    //        步驟五:儲存到陣列中,更新UI
    people.append(person)
}
複製程式碼

所有的原始碼在這裡哈:GitHub 下載後給顆Star吧~ 麼麼噠~(~o ̄3 ̄)~ 愛你們~

相關文章