CoreData 是 iOS3.0 时引入的一个数据持久化的框架。利用这个框架我们可以非常方便的对数据进行操作。
可以先从一个简单的例子来看一下CoreData到底能干啥:
首先我们要新建一个单页面项目,勾选选项CoreData;
然后在storyboard中拖一个tableView到ViewController上,并导入一个NavigationController,在导航栏上添加一个button(此处不是CoreData的重点所以我们简单叙述),同时与代码建立关联;
然后打开 项目名.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)
现在开始实现功能,功能很简单就是点击添加按钮添加一个name到表格中,数据在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是否符合条件 符合的话就执行下面的代码 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest(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是否符合条件 符合的话就执行下面的代码 不符合直接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
}
}
现在解释一下涉及到CoreData的一些代码:
var people:[NSManagedObject] = []
我们将people这个数组定义为NSManagedObject类型,NSManagedObject类代表存储在CoreData中的一个单独的对象,而且它很灵活,在你的数据模型中,它可以采取任何实体的形式。
cell.textLabel?.text = person.value(forKeyPath: "name") as? String
我们如何从实体中得到属性呢?通过KVC
简单说一下KVC,就是指在iOS开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态在访问和修改对象的属性。而不是在编译时确定。具体关于KVC的知识还在探索中......(手动尴尬)
func save(name:String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
} //判断appDelegate是否符合条件 符合的话就执行下面的代码 不符合直接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来保存数据,需要两个步骤:
(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是否符合条件 符合的话就执行下面的代码 不符合直接return退出
let manageContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest(entityName: "Person")
do {
people = try manageContext.fetch(fetchRequest) //抛出异常
} catch let error as NSError {
print("无法读取!\(error),\(error.userInfo)")
}
}
最后,保存到CoreData中的数据需要被取出才能显示,需要注意的是:伴随CoreData进行的任何操作都需要一个managed object context。
最后的结果:
在CoreData中,可以给实体定义很多属性(废话(⊙o⊙)…),不同的属性对应不同的种类,有以下几种:
常见的几个就不多说了,说说两个不常见的:Binary Data和Transformable
Binary Data顾名思义,二进制数据,任何可序列化为0和1的属性都可以使用这个种类,比如图片,PDF等等,看似变得方便了,但是当你的二进制数据很庞大时它会影响到程序的表现,试想一下每次访问实体的时候都要加载大量的二进制数据,甚至你可能只是想访问实体的名称......
还好CoreData提供了解决方法,就是当你选择了二进制数据作为你属性的种类时,你可以同时勾选Allows External Storage,如图:
接下来说说Transformable
在CoreData中,我们可以选择任何数据类型,甚至是我们自己定义的,我们只需要将类型选择为Transformable并且遵循NSCoding协议即可。
NSCoding协议目前我还不是很清楚,在以后的学习中会加入到文章中来。
CoreData的学习才刚刚开始,一些概念还理解得并不是很透彻,在今后的学习中还要不断完善自己。