转载

[Swift] Core Data 入門

[Swift] Core Data 入門

什麼是 Core Data

在 iOS(OSX) 應用程式中,要儲存資料可以使用資料庫或檔案,以及現在要介紹的 Core Data,所以 Core Data 的用途就是儲存資料。Core Data 是在 OSX 10.4 及 iOS 3.0 之後開始使用,它可以將物件序列化後儲存在 XML、binary(二位元檔)或SQLite資料庫。

Core Data 是一個儲存資料的框架,它的底層本質上還是使用 SQLite 資料庫,它提供簡單易用的方式讓你儲存資料,而不用撰寫複雜的 SQL 語法。如果你的專案有使用 Core Data,可以在該 App 的 Document 目錄中找到 sqlite 檔案。

關於效能的問題,到底直接使用 SQLite 好,還是使用 Core Data 好,可以參考這篇文章 iOS Data Storage: Core Data vs. SQLite 。簡單來說,Core Data 是以空間換取時間,意思是比較佔記憶體空間,但速度比較快;另外一個好處是,使用 Core Data 的程式碼比較簡單易讀,不會有複雜的 SQL 語法,官方的說法是,會減少 50~70% 的程式碼。

Managed Object Model(託管物件模型)

大部份的 Core Data 的功能,依賴你所建立的綱要(schema)去描述應用程式的實體(Entity),包含屬性及關聯等等。Core Data 使用一個被稱為 Managed object model 的網要(shcema),它是一個 NSManagedObjectModel 物件的實體。

簡單的說,一個 Managed object model 會對應到資料儲存(persistent store)的一組紀錄,這裡的 persistent store 相當於資料庫;而 Managed object model 即一組紀錄,相當於資料表(table)。

由於 Core Data 並不把自己當成關聯式資料庫(雖然它的底層是使用 SQLite,但這只是它的儲存格式之一),它把這些傳統關聯式資料庫的概念抽象化,所以這邊在說明時會在抽象的定義中,以關聯式資料庫的概念來類比。

因此:

  • NSManagedObjectModel 相當於所有 table 的集合
  • NSPersistentStoreCoordinator 相當於 database(SQLite)

一個實體描述(entity description)表示一個實體(即table),實體(Entity)有一個類別名稱,用來表示 Entity,並且會有特質(property)來表示屬性(attribute)及實體間的關聯(relationship)。一群 Entity (table)組合起來就是 Model。使用 NSEntityDescription 物件用來操作實體描述。

因此,在 Core Data 中:

會有一個 Model(=資料庫), 包含至少一個 Entity(=資料表), 這個 Entity 會有屬性及關聯(=欄位)。

範例 - 使用 Core Data 建立基本的 CRUD 功能

註:本範例使用 XCode 7.0 及 Swift 2.0

開啟 XCode ,建立一個 Single View Application 專案:

[Swift] Core Data 入門

專案名稱為 CoreDataDemo,記得勾選 Core Data 選項:

[Swift] Core Data 入門

當你勾選 Core Data 時,在 AppDelegate.swift 中會被加入 Core Data 相關的程式碼。你會在其中找到像是 "SingleViewCoreData.sqlite" 這段字串,這就是你的 SQLite 資料庫的名稱。

只要在建立專案時有勾選 Core Data,XCode 就會自動產生一個 *.xcdatamodeld 檔案,選擇它會開啟 model (即database)的管理界面:

[Swift] Core Data 入門

目前這個資料庫是空的,讓我們來加第一個實體(Entity,即table)。點選下方的 "Add Entity",在左邊欄的會出現新的 "Entity" 項目,你可以點選它來改名,或在右邊欄中改名。我們將名稱改為 "Product":

[Swift] Core Data 入門

接著新增這個 Product entity 的屬性(Attirbutes),點選 Attributes 欄位下方的 "+" (或下方的 "Add Attribute" 也可以)即可新增。加入 name 及 price 兩個屬性,並且選擇它的 Type:

[Swift] Core Data 入門

再來要讓程式碼中可以使用這個 Entity,我們要建立一個 Product 類別,並且繼承 NSManagedObject。XCode 可以幫我們自動產生,在選單列中選擇 Editor > Create NSManagedObject Subclass...:

[Swift] Core Data 入門

選擇要產生的 Data Model 及 Entity 之後,將要產生的檔案選擇建立在專案中。

XCode 會產生兩個檔案:

Product.swift:

import Foundation import CoreData class Product: NSManagedObject {     // Insert code here to add functionality to your managed object subclass } 

Product+CoreDataProperties.swift:

import Foundation import CoreData extension Product {     @NSManaged var name: String?     @NSManaged var price: NSNumber? } 

Product+CoreDataProperties.swift 用來存放 Entity 的屬性,Product.swift 就專心在該 Entity 要提供的方法。你會注意到這個 Product 類別是繼承 NSManagedObject。

註:如果不知道為什麼這裡會有兩個檔案,可以研究一下 Swift 的 extension 功能,它和 Objective-C 的 Category 是同樣用途。

NSManagedObject 類別的屬性是 @NSManaged,表示它是受管理的,因此我們不必再去寫 getter/setter 或檢查資料型態是否符合等等的工作。

新增

前置工作都完成後,就可以開始寫程式了,首先,我們要新增一筆資料,打開 ViewController.swift,加入新增資料的程式碼:

let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext override func viewDidLoad() {  super.viewDidLoad()  self.addProduct("iPhone 6s 16GB", price: 24500) } func addProduct(name:String, price:Int) {  let product = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: self.moc) as! Product  product.name = name  product.price = price  do {   try self.moc.save()  }catch{   fatalError("Failure to save context: /(error)")  } }  

註:記得先 import CoreData,否則可能會出現找不到類別的錯誤。

XCode 在 AppDelegate 中幫我們建立了 managedObjectContext 這個參考到 NSManagedObjectContext 類別的變數,任何對資料表的操作都必須透過它,所以第一步就是先取得它。

addProduct() 方法用來新增產品,要新增資料到資料表,必須透過 NSEntityDescription 類別的 insertNewObjectForEntityForName() 方法,第一個參數是 Entity 的名稱,第二個參數則是 NSManagedObjectContext,這個方法會回傳我們要求的 Entity,接著只要對該 Entity 的屬性給值即可。

動作到此為止,資料表中已經有一筆資料了,可是目前的動作都僅存在於記憶體中,如果這時把程式關閉,這些資料就會消失。因此,最後記得要呼叫 NSManagedObjectContext 的 save() 方法真正的把資料儲存下來。

查詢

來看看剛才新增的產品是否有新增成功。加入顯示全部產品的方法:

func showProducts() {  let request = NSFetchRequest(entityName: "Product")  do {   let results = try moc.executeFetchRequest(request) as! [Product]   for result in results {    print("Product Name: /(result.name!), Price: /(result.price!)")   }  }catch{   fatalError("Failed to fetch data: /(error)")  } }  

然後在原本新增產品的後面加入此方法:

self.addProduct("iPhone 6s 16GB", price: 24500) self.showProducts() 

我執行了 3 次後,結果如下:

[Swift] Core Data 入門

刪除

因為每次重新執行程式時,就會新增一次重覆的資料,我們並不想這樣,所以在每次重新執行時,就把資料表清空,把裡面的資料全部刪除。

func cleanUpProducts() {  let request = NSFetchRequest(entityName: "Product")  do {   let results = try moc.executeFetchRequest(request) as! [Product]   for result in results {    moc.deleteObject(result)   }  }catch{   fatalError("Failed to fetch data: /(error)")  } }  

刪除的動作是,先如同查詢的動作一樣,把資料表中的資料全部取出,然後使用 NSManagedObjectContext 物件的 deleteObject() 方法來一一刪除。

現在 viewDidLoad() 裡是這樣:

self.cleanUpProducts() self.addProduct("iPhone 6s 16GB", price: 24500) self.showProducts() 

更新

更新的動作,就是先找到該筆資料,修改它的屬性值,然後儲存就完成了。這裡假設要新增三筆資料,但有一筆的價格打錯了,於是把它更新。現在的 viewDidLoad():

self.cleanUpProducts() self.addProduct("iPhone 6s 16GB", price: 24500) self.addProduct("iPhone 6s 64GB", price: 28500) self.addProduct("iPhone 6s 128GB", price: 22500) self.updateProductPrice() self.showProducts() 

我們要找到 22500 這筆資料,把它改成 32500,新增一個方法:

func updateProductPrice(){  let request = NSFetchRequest(entityName: "Product")  request.predicate = NSPredicate(format: "name == %@", "iPhone 6s 128GB")  do{   let results = try moc.executeFetchRequest(request) as! [Product]   if (results.count > 0){    let product = results[0]    product.price = 32500    try self.moc.save()   }  } catch {   fatalError("Failed to update data: /(error)")  } }  

在原本的查詢中,指定 request 的 predicate 屬性來過濾資料,找到後,只要將新的值指定給它,然後儲存,這樣就完成更新了。

[Swift] Core Data 入門

NSPredicate 的設定方法和 SQL 語法很像,詳細內容可以參考 這裡 。

以上是最基本的 Core Data 的 CRUD 操作。

參考資料

  • Core Data(Wiki)
  • Core Data Programming Guide
  • Core Data in Swift Tutorial
  • NSPredicate Cheatsheet
  • Core Data Part 2: Update, Delete Managed Objects and View Raw SQL Statement
  • iOS Data Storage: Core Data vs. SQLite

Written by Tony at Tony Blog - http://blog.tonycube.com/

----

正文到此结束
Loading...