Core Data 是什麼樣子的

Core Data 是 iOS3.0 時引入的一個數據持久化的框架。與 sqlite 對比最大的優勢莫過於支持對象的存儲,蘋果的官方文檔說其簡化了數據庫的操做,使用 Core Data 確實能夠大量減小代碼中的 SQL 語句。sql

但是現狀,你們對於持久化的選擇方案仍多數是 FMDB。筆者猜想,最大的緣由可能就是性能。數據庫

各類持久化方案性能比較

Core Data 是什麼

Core Data 是一個模型層的技術,幫助開發者創建表明程序狀態的模型層。同時也是一種持久化技術,它能將模型對象的狀態持久化到磁盤。它是徹底獨立於 UI 層級的框架,是做爲模型層框架被設計出來的。swift

Core Data 不是一個 O/RM,但它比 O/RM 能作的更多。它也不是一個 SQL wrapper。它默認使用 SQL,但它是一種更高級的抽象概念。緩存

堆棧

Core Data 有至關多可用的組件。當全部的組件都捆綁到一塊兒的時候,咱們把它稱做 Core Data 堆棧,這個堆棧有兩個主要部分。多線程

一部分是關於對象圖管理,這正是你須要很好掌握的那一部分,而且知道怎麼使用。 另外一部分是關於持久化,好比,保存你模型對象的狀態,而後再恢復模型對象的狀態。app

堆棧結構以下框架

Core Data 堆棧

NSPersistentStoreCoordinator 是一個位於本地存儲文件與緩存層(NSManagedObjectContext)之間的一個持久化層,它是真實操做數據庫本地文件。ide

NSManagedObjectContext 是一個被管理數據的上下文,它其實是對全部數據庫操做的一個緩存層,把全部的操做都先緩存起來避免大量磁盤 IO 形成不流暢,在操做完數據庫後調用其 save 方法,就能夠把數據庫操做提交給持久化層(NSPersistentStoreCoordinator),由持久化層一次性寫入數據庫文件。性能

NSManagedObject 是被管理的數據記錄,對應數據庫的一個表。學習

另外,Core Data 能夠將多個 stores 附屬於同一個持久化存儲協調器,而且除了存儲 SQL 格式外,還有不少存儲類型可供選擇。 最多見的方案以下

多個 stores 持久化

實際使用

下面是筆者定義的一個 Event 表的元素組成

數據表元素

定義數據模型

class MXWEventModel: NSObject {
    var id: Int64
    var time: Date
    var title: String
    var detail: String
    var addr: String
    
    init(id: Int64, title: String, detail: String, addr: String, time: Date){}
}
複製代碼

新增數據

let context = persistentContainer.viewContext

public func add(model: AnyObject) {
	let eventModel: MXWEventModel = model as! MXWEventModel
	let entity = NSEntityDescription.entity(forEntityName: @"MXWEvent", in: context!)
	let obj = NSManagedObject(entity: entity!, insertInto: context)
	obj.setValue(eventModel.id, forKey: "id")
	obj.setValue(eventModel.title, forKey: "title")
	obj.setValue(eventModel.detail, forKey: "detail")
	obj.setValue(eventModel.time, forKey: "time")
	obj.setValue(eventModel.addr, forKey: "addr")
	do {
		try context?.save()
	} catch {
		print(error)
	}
}
複製代碼

刪除數據

public func delete(id: Int64) {
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
	do {
		try context?.execute(deleteRequest)
	} catch {
		print(error)
	}
}
複製代碼

修改數據

public func update(id: Int64, model: AnyObject) {
	let eventModel: MXWEventModel = model as! MXWEventModel
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	do {
		let eventObj = try context?.fetch(request)
		let updateObj = eventObj?.first as! NSManagedObject
		updateObj.setValue(eventModel.title, forKey: "title")
		updateObj.setValue(eventModel.detail, forKey: "detail")
		updateObj.setValue(eventModel.time, forKey: "time")
		updateObj.setValue(eventModel.addr, forKey: "addr")
		do {
			try context?.save()
		} catch {
			print(error)
		}
	} catch {
		print(error)
	}
}
複製代碼

查找數據

public func fetch(id: Int64) -> AnyObject? {
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	do {
		let r = try context?.fetch(request)
		for data in r as! [NSManagedObject] {
			let m = MXWEventModel(id: data.value(forKey: "id") as! Int64, title: data.value(forKey: "title") as! String, detail: data.value(forKey: "detail") as! String, addr: data.value(forKey: "addr") as! String, time: data.value(forKey: "time") as! Date)
			return m
		}
	} catch {
		print(error)
	}
}
複製代碼

高級功能

數據遷移

在功能迭代過程當中,不免會遇到要修改 .xcdatamodeld 文件。例如,新增或刪除一個實體、增長或刪除一個原有實體的屬性等。若是開發者沒有設置數據遷移,那更新後原有的數據將會被清空,因此此時須要進行數據的遷移操做。

Core Data 能夠設置輕量級的數據遷移,系統會自動分析差別,進行映射,這種方式只適用於簡單的增刪實體或是增刪屬性等操做。除此以外還有一種至關複雜的自定義數據遷移。

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "Demo")
    container.loadPersistentStores(completionHandler: { storeDescription, error in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
        // 設置數據遷移(shouldMigrateStoreAutomatically 默認值爲 true)
        if let sDescription: NSPersistentStoreDescription = storeDescription as NSPersistentStoreDescription {
            sDescription.shouldMigrateStoreAutomatically = true
            sDescription.shouldInferMappingModelAutomatically = false
        }
    })
    return container
}()
複製代碼

思考

對於 Core Data,Apple 官方好久以前就已經推出,可是並不受開發者青睞。筆者在這段時間的學習過程當中也在思考這個問題。

下面是筆者學習中遇到的注意點:

  1. Core Data 中沒有自增數據類型。由於 Core Data 不能使用數據庫思惟去使用,因此也就很好解釋了。
  2. 設置 context 的 merge 策略,減小數據遷移的麻煩。
  3. 最好使用多線程,能夠進一步提高性能。

最後,文章開頭給出了性能比較。可是,筆者認爲,在客戶端並無很大量的數據寫入,只要開發者在使用過程當中稍做注意,性能應該不是否決 Core Data 技術方案的理由。反倒,Core Data 對 iCloud 很好的支持,以及數據遷移備份,這些均可以很容易實現。筆者認爲,徹底能夠考慮使用它作客戶端的數據持久化方案。

參考文檔

《Core Data Programming Guide》

相關文章
相關標籤/搜索