CoreData作為Apple的親兒子,依然在App需要存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)上發(fā)揮著重要的作用。CoreData已經(jīng)超過十年了拗胜,而且親爹還在積極的維護(hù)著它。
在Monster怒允、Indeed這些海外主流招聘網(wǎng)站看一下iOS的職位埂软,基本上都會(huì)大大寫著要求會(huì)熟練使用CoreData。
然而這么一個(gè)成熟纫事,被實(shí)踐檢驗(yàn)過的代碼庫反而在國內(nèi)使用并不是特別多勘畔。FMDB、Realm等等在被廣泛使用丽惶。經(jīng)常在面試的時(shí)候問iOSer是不是了解數(shù)據(jù)庫炫七,回答都是了解。再一細(xì)問钾唬,很多人也都是只使用到了FMDB万哪,對(duì)于CoreData卻是了解甚少。
后來想了想抡秆,可能是因?yàn)镃oreData的入門成本有點(diǎn)高奕巍,而且相關(guān)的中文資料比較少的緣故吧。
為了寫這個(gè)系列儒士,還專門買來了objc.io的CoreData這本書的止。讀完之后受益匪淺。
這個(gè)系列要寫多少篇還沒有想好着撩,大概也還是會(huì)從基本到高級(jí)的一個(gè)過渡诅福。
第一篇通過一個(gè)通訊錄實(shí)現(xiàn)數(shù)據(jù)庫的讀取。第二篇會(huì)存儲(chǔ)更多類型的數(shù)據(jù)睹酌。
最終實(shí)現(xiàn)結(jié)果:
1. Core Data架構(gòu)
一個(gè)基本的 Core Data 棧由四個(gè)主要部分組成:托管對(duì)象 (NSManagedObject)权谁,托管對(duì)象上下文 (NSManagedObjectContext)剩檀,持久化存儲(chǔ)協(xié)調(diào)器 (NSPersistentStoreCoordinator)憋沿,以及持久化存儲(chǔ) (NSPersistentStore)。
NSManagedObject是我們的數(shù)據(jù)模型沪猴,也就是我們存儲(chǔ)的對(duì)象辐啄。這些對(duì)象都保存在NSManagedObjectContext中采章,每個(gè)存儲(chǔ)對(duì)象都知道自己對(duì)應(yīng)哪個(gè)上下文。
NSManagedObjectContext :日常打交道的都是這個(gè)壶辜。其他三個(gè)在數(shù)據(jù)遷移的時(shí)候才會(huì)看到悯舟。
NSPersistenStoreCoordinator :
是模型和存儲(chǔ)數(shù)據(jù)庫之間的橋梁,負(fù)責(zé)兩者之間最復(fù)雜的細(xì)節(jié)隱藏砸民。
關(guān)于Context想多說點(diǎn)抵怎,因?yàn)槭翘焯於即蚪坏赖穆铩K鋵?shí)是內(nèi)存中的一塊區(qū)域岭参,對(duì)象所有的操作都需要一個(gè)context反惕。直到save之前,都是在內(nèi)存中演侯,不會(huì)對(duì)數(shù)據(jù)庫中的內(nèi)容有任何影響姿染。每一個(gè)托管對(duì)象都對(duì)應(yīng)一個(gè)Context,一個(gè)對(duì)象只會(huì)跟一個(gè)特定的Context打交道秒际。直到生命周期結(jié)束悬赏。
Context是線程不安全的。
2. CoreData的基本讀取操作
2. 1 獲取CoreData已經(jīng)保存數(shù)據(jù)的五個(gè)步驟
- 獲取總代理和托管對(duì)象總管
- 從Entity獲取一個(gè)fetchRequest
- 根據(jù)fetchRequest娄徊,從managedContext中查詢數(shù)據(jù)
- 保存闽颇。保存過程中可能會(huì)出錯(cuò),要做一下處理寄锐。
- 添加到數(shù)組中
2.2 基本存儲(chǔ)
- 獲取總代理和托管對(duì)象總管
- 建立一個(gè)Entity
- 保存內(nèi)容
- 保存Entity到托管對(duì)象进萄。如果保存失敗,進(jìn)行處理
- 保存到數(shù)組中锐峭,更新UI
3. 更新一個(gè)通訊錄的列表頁Demo
需求:完成一個(gè)通訊錄的列表頁中鼠。要求:
- 從本地?cái)?shù)據(jù)庫中讀取名字列表
- 點(diǎn)擊增加可以添加一個(gè)名字
- 添加的名字可以保存到本地?cái)?shù)據(jù)庫中
好,接下來咱們來一步一步實(shí)現(xiàn)這個(gè)需求沿癞。為了突出重點(diǎn)援雇,咱們先從最簡單的開始,使用默認(rèn)帶數(shù)據(jù)庫的工程進(jìn)行著手椎扬。
3.1 Xcode創(chuàng)建默認(rèn)帶數(shù)據(jù)庫的工程
在 Xcode 創(chuàng)建工程時(shí)惫搏,提供了創(chuàng)建 CoreData 的模板,只需要我們?cè)趧?chuàng)建時(shí)蚕涤,勾選 CoreData 選項(xiàng)筐赔,Xcode 就會(huì)自動(dòng)創(chuàng)建出數(shù)據(jù)模型文件。
這個(gè)Demo用這個(gè)創(chuàng)建揖铜,純粹是為了簡單直奔主題茴丰。不然還要一開始分享很多其他的內(nèi)容,看官們會(huì)覺得膩的。
但是贿肩,實(shí)際開發(fā)中不建議使用這種方式創(chuàng)建峦椰。通常情況下我們都會(huì)把生成的模板代碼都刪除的。
3.2 創(chuàng)建本地?cái)?shù)據(jù)庫模板
勾選完成之后汰规,會(huì)看到一個(gè)后綴名是"xcdatamodeld"的文件汤功,這個(gè)就是咱們的數(shù)據(jù)庫模板啦。
當(dāng)然溜哮,現(xiàn)在里面是還不能存數(shù)據(jù)的滔金,還需要我們?cè)O(shè)置一下字段名稱。
第一步茂嗓,要添加一個(gè)Entity鹦蠕,這個(gè)就相當(dāng)于是數(shù)據(jù)庫中的一張表。
第二步在抛,對(duì)新建的Entity命名钟病。
第三步,設(shè)計(jì)Entity里面的屬性刚梭。咱們這個(gè)Demo的需求里面只需要一個(gè)人名肠阱,所以就只設(shè)置了一個(gè)名字叫做name的屬性,類型是String朴读。
其他更多的屬性類型屹徘,我們會(huì)在下面一篇文章分享。
3.3 查詢本地?cái)?shù)據(jù)
咦衅金?在最開始的不是說一個(gè)基本的 Core Data 棧由四個(gè)主要部分組成嘛噪伊?怎么沒有看到吶?
來來來氮唯,這就是最開始我們使用Xcode創(chuàng)建默認(rèn)帶數(shù)據(jù)庫的工程的原因鉴吹。使用了這個(gè)選項(xiàng),會(huì)自動(dòng)的在AppDelegate
中生成相應(yīng)的代碼惩琉。確實(shí)簡化了咱們第一次學(xué)習(xí)的成本豆励,但是就像沒人會(huì)把所有代碼都寫在Controller里面一樣,在APPDelegate也不會(huì)寫這些東西瞒渠。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 步驟一:獲取總代理和托管對(duì)象總管
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedObectContext = appDelegate.persistentContainer.viewContext
// 步驟二:建立一個(gè)獲取的請(qǐng)求
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
// 步驟三:執(zhí)行請(qǐng)求
do {
let fetchedResults = try managedObectContext.fetch(fetchRequest) as? [NSManagedObject]
if let results = fetchedResults {
people = results
tableView.reloadData()
}
} catch {
fatalError("獲取失敗")
}
}
3.4 插入并保存數(shù)據(jù)至本地?cái)?shù)據(jù)庫
private func saveName(text: String) {
// 步驟一:獲取總代理和托管對(duì)象總管
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedObectContext = appDelegate.persistentContainer.viewContext
// 步驟二:建立一個(gè)entity
let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedObectContext)
let person = NSManagedObject(entity: entity!, insertInto: managedObectContext)
// 步驟三:保存文本框中的值到person
person.setValue(text, forKey: "name")
// 步驟四:保存entity到托管對(duì)象中良蒸。如果保存失敗,進(jìn)行處理
do {
try managedObectContext.save()
} catch {
fatalError("無法保存")
}
// 步驟五:保存到數(shù)組中伍玖,更新UI
people.append(person)
}
所有的源代碼在這里哈:
https://github.com/Stanbai/CoreDataDemo.git
Swift之CoreData系列之一:基礎(chǔ)存儲(chǔ)