CoreData 是 iOS3.0 時引入的一個數(shù)據(jù)持久化的框架。利用這個框架我們可以非常方便的對數(shù)據(jù)進行操作。
可以先從一個簡單的例子來看一下CoreData到底能干啥:
首先我們要新建一個單頁面項目,勾選選項CoreData;


然后在storyboard中拖一個tableView到ViewController上,并導入一個NavigationController,在導航欄上添加一個button(此處不是CoreData的重點所以我們簡單敘述),同時與代碼建立關聯(lián);



然后打開 項目名.xcdatamodeld,新建一個實體Person和一個實體的屬性name
![屏幕快照 2016-10-23 下午9.14.37_545952.png]
](http://upload-images.jianshu.io/upload_images/1830151-ef898efbe2c4719e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

現(xiàn)在開始實現(xiàn)功能,功能很簡單就是點擊添加按鈕添加一個name到表格中,數(shù)據(jù)在app退出后始終保存
ViewController.swift代碼如下:
import UIKit
import CoreData
class ViewController: UIViewController {
@IBOutlet weak var tabelView:UITableView!
@IBAction func addName(_ sender:UIBarButtonItem) {
let alert = UIAlertController(title: "姓名", message: "請輸入姓名:", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "保存", style: .default) {
[unowned self] action in
guard let textField = alert.textFields?.first,
let nameToSave = textField.text else {
return
}
self.save(name: nameToSave)
self.tabelView.reloadData()
}
let cancelAction = UIAlertAction(title: "取消", style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert,animated: true)
}
//var names:[String] = []
var people:[NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "列表"
tabelView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
} //判斷appDelegate是否符合條件 符合的話就執(zhí)行下面的代碼 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Person")
do {
people = try manageContext.fetch(fetchRequest) //拋出異常
} catch let error as NSError {
print("無法讀取!\(error),\(error.userInfo)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func save(name:String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
} //判斷appDelegate是否符合條件 符合的話就執(zhí)行下面的代碼 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Person", in: manageContext)!
let person = NSManagedObject(entity: entity, insertInto: manageContext)
person.setValue(name, forKey: "name")
do {
try manageContext.save() //拋出異常
people.append(person)
} catch let error as NSError {
print("無法保存!\(error),\(error.userInfo)")
}
}
}
//UITableViewDataSource
extension ViewController:UITableViewDataSource {
func tableView(_ tableView:UITableView,numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath) -> UITableViewCell {
let person = people[indexPath.row]
let cell = tabelView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = person.value(forKeyPath: "name") as? String
return cell
}
}
現(xiàn)在解釋一下涉及到CoreData的一些代碼:
var people:[NSManagedObject] = []
我們將people這個數(shù)組定義為NSManagedObject類型,NSManagedObject類代表存儲在CoreData中的一個單獨的對象,而且它很靈活,在你的數(shù)據(jù)模型中,它可以采取任何實體的形式。
cell.textLabel?.text = person.value(forKeyPath: "name") as? String
我們?nèi)绾螐膶嶓w中得到屬性呢?通過KVC
簡單說一下KVC,就是指在iOS開發(fā)中,可以允許開發(fā)者通過Key名直接訪問對象的屬性,或者給對象的屬性賦值。而不需要調(diào)用明確的存取方法。這樣就可以在運行時動態(tài)在訪問和修改對象的屬性。而不是在編譯時確定。具體關于KVC的知識還在探索中......(手動尷尬)
func save(name:String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
} //判斷appDelegate是否符合條件 符合的話就執(zhí)行下面的代碼 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Person", in: manageContext)!
let person = NSManagedObject(entity: entity, insertInto: manageContext)
person.setValue(name, forKey: "name")
do {
try manageContext.save() //拋出異常
people.append(person)
} catch let error as NSError {
print("無法保存!\(error),\(error.userInfo)")
}
}
我們要通過CoreData來保存數(shù)據(jù),需要兩個步驟:
(1)將一個managed object添加到一個managed object context中;
(2)在managed object context中實行改變并保存。
override func viewWillAppear(_ animated: Bool) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
} //判斷appDelegate是否符合條件 符合的話就執(zhí)行下面的代碼 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Person")
do {
people = try manageContext.fetch(fetchRequest) //拋出異常
} catch let error as NSError {
print("無法讀取!\(error),\(error.userInfo)")
}
}
最后,保存到CoreData中的數(shù)據(jù)需要被取出才能顯示,需要注意的是:伴隨CoreData進行的任何操作都需要一個managed object context。
最后的結(jié)果:

在CoreData中,可以給實體定義很多屬性(廢話(⊙o⊙)…),不同的屬性對應不同的種類,有以下幾種:

常見的幾個就不多說了,說說兩個不常見的:Binary Data和Transformable
Binary Data顧名思義,二進制數(shù)據(jù),任何可序列化為0和1的屬性都可以使用這個種類,比如圖片,PDF等等,看似變得方便了,但是當你的二進制數(shù)據(jù)很龐大時它會影響到程序的表現(xiàn),試想一下每次訪問實體的時候都要加載大量的二進制數(shù)據(jù),甚至你可能只是想訪問實體的名稱......
還好CoreData提供了解決方法,就是當你選擇了二進制數(shù)據(jù)作為你屬性的種類時,你可以同時勾選Allows External Storage,如圖:

接下來說說Transformable
在CoreData中,我們可以選擇任何數(shù)據(jù)類型,甚至是我們自己定義的,我們只需要將類型選擇為Transformable并且遵循NSCoding協(xié)議即可。
NSCoding協(xié)議目前我還不是很清楚,在以后的學習中會加入到文章中來。
CoreData的學習才剛剛開始,一些概念還理解得并不是很透徹,在今后的學習中還要不斷完善自己。