CoreData 作为 Apple 的亲儿子, 依然在 App 需要存储结构化数据上发挥着重要的作用 CoreData 已经超过十年了, 而且亲爹还在积极的维护着它
在 MonsterIndeed 这些海外主流招聘网站看一下 iOS 的职位, 基本上都会大大写着要求会熟练使用 CoreData
然而这么一个成熟, 被实践检验过的代码库反而在国内使用并不是特别多 FMDBRealm 等等在被广泛使用经常在面试的时候问 iOSer 是不是了解数据库, 回答都是了解再一细问, 很多人也都是只使用到了 FMDB, 对于 CoreData 却是了解甚少
后来想了想, 可能是因为 CoreData 的入门成本有点高, 而且相关的中文资料比较少的缘故吧
为了写这个系列, 还专门买来了 objc.io 的 CoreData 这本书读完之后受益匪浅
这个系列要写多少篇还没有想好, 大概也还是会从基本到高级的一个过渡
第一篇通过一个通讯录实现数据库的读取第二篇会存储更多类型的数据
最终实现结果:
1. Core Data 架构
一个基本的 Core Data 栈由四个主要部分组成: 托管对象 (NSManagedObject), 托管对象上下文 (NSManagedObjectContext), 持久化存储协调器 (NSPersistentStoreCoordinator), 以及持久化存储 (NSPersistentStore)
NSManagedObject 是我们的数据模型, 也就是我们存储的对象这些对象都保存在 NSManagedObjectContext 中, 每个存储对象都知道自己对应哪个上下文
NSManagedObjectContext : 日常打交道的都是这个其他三个在数据迁移的时候才会看到
NSPersistenStoreCoordinator : 是模型和存储数据库之间的桥梁, 负责两者之间最复杂的细节隐藏
关于 Context 想多说点, 因为是天天都打交道的嘛它其实是内存中的一块区域, 对象所有的操作都需要一个 context 直到 save 之前, 都是在内存中, 不会对数据库中的内容有任何影响每一个托管对象都对应一个 Context, 一个对象只会跟一个特定的 Context 打交道直到生命周期结束
Context 是线程不安全的
2. CoreData 的基本读取操作
2. 1 获取 CoreData 已经保存数据的五个步骤
获取总代理和托管对象总管
从 Entity 获取一个 fetchRequest
根据 fetchRequest, 从 managedContext 中查询数据
保存保存过程中可能会出错, 要做一下处理
添加到数组中
2.2 基本存储
获取总代理和托管对象总管
建立一个 Entity
保存内容
保存 Entity 到托管对象如果保存失败, 进行处理
保存到数组中, 更新 UI
3. 更新一个通讯录的列表页 Demo
需求: 完成一个通讯录的列表页要求:
从本地数据库中读取名字列表
点击增加可以添加一个名字
添加的名字可以保存到本地数据库中
好, 接下来咱们来一步一步实现这个需求为了突出重点, 咱们先从最简单的开始, 使用默认带数据库的工程进行着手
3.1 Xcode 创建默认带数据库的工程
在 Xcode 创建工程时, 提供了创建 CoreData 的模板, 只需要我们在创建时, 勾选 CoreData 选项, Xcode 就会自动创建出数据模型文件
这个 Demo 用这个创建, 纯粹是为了简单直奔主题不然还要一开始分享很多其他的内容, 看官们会觉得腻的
但是, 实际开发中不建议使用这种方式创建通常情况下我们都会把生成的模板代码都删除的
3.2 创建本地数据库模板
勾选完成之后, 会看到一个后缀名是 "xcdatamodeld" 的文件, 这个就是咱们的数据库模板啦
当然, 现在里面是还不能存数据的, 还需要我们设置一下字段名称
第一步, 要添加一个 Entity, 这个就相当于是数据库中的一张表
第二步, 对新建的 Entity 命名
第三步, 设计 Entity 里面的属性咱们这个 Demo 的需求里面只需要一个人名, 所以就只设置了一个名字叫做 name 的属性, 类型是 String
其他更多的属性类型, 我们会在下面一篇文章分享
3.3 查询本地数据
咦? 在最开始的不是说一个基本的 Core Data 栈由四个主要部分组成嘛? 怎么没有看到呐?
来来来, 这就是最开始我们使用 Xcode 创建默认带数据库的工程的原因使用了这个选项, 会自动的在 AppDelegate 中生成相应的代码确实简化了咱们第一次学习的成本, 但是就像没人会把所有代码都写在 Controller 里面一样, 在 APPDelegate 也不会写这些东西
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- // 步骤一: 获取总代理和托管对象总管
- let appDelegate = UIApplication.shared.delegate as! AppDelegate
- let managedObectContext = appDelegate.persistentContainer.viewContext
- // 步骤二: 建立一个获取的请求
- let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
- // 步骤三: 执行请求
- do {
- let fetchedResults = try managedObectContext.fetch(fetchRequest) as? [NSManagedObject]
- if let results = fetchedResults {
- people = results
- tableView.reloadData()
- }
- } catch {
- fatalError("获取失败")
- }
- }
3.4 插入并保存数据至本地数据库
- private func saveName(text: String) {
- // 步骤一: 获取总代理和托管对象总管
- let appDelegate = UIApplication.shared.delegate as! AppDelegate
- let managedObectContext = appDelegate.persistentContainer.viewContext
- // 步骤二: 建立一个 entity
- let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedObectContext)
- let person = NSManagedObject(entity: entity!, insertInto: managedObectContext)
- // 步骤三: 保存文本框中的值到 person
- person.setValue(text, forKey: "name")
- // 步骤四: 保存 entity 到托管对象中如果保存失败, 进行处理
- do {
- try managedObectContext.save()
- } catch {
- fatalError("无法保存")
- }
- // 步骤五: 保存到数组中, 更新 UI
- people.append(person)
- }
所有的源代码在这里哈: GitHub https://github.com/Stanbai/CoreDataDemo
来源: https://juejin.im/post/5aa544216fb9a028c3686bed