如何在CoreData中创建一个Model
假设现在需要创建一个Robot的类,里面有基本数据类型id
和name
属性,还有另外一个自定义RobotArm的属性arm
, 那么该如何在CoreData里面使用呢?
Class Robot: NSManagedObject {
@NSManaged public var id: Int16
@NSManaged public var name: String?
@NSManaged public var arm: RobotArm?
}
1. 首先创建一个Robot Entity
image.png
会看到侧边栏有Codegen Options选项
Q&A 这些选项的区别是什么?
Options | Meaning |
---|---|
Manual/None | iOS之前是手动创建和维护 NSManagedObject 子类的文件 |
Class Definition | 使用了这个选项,不需要创建对应类的file,编译完就能使用这个类 |
Category/Extension | 使用类别/扩展选项,可以完全控制类文件,同时继续自动生成属性文件以使其与模型编辑器保持同步。 |
详情可以看官方文档: Apple Document
简单点说:
- 选择Manual/None就需要手动去创建对应的类文件(
Robot+CoreDataClass
和Robot+CoreDataProperties
); - 选择Class Definition会在编译时生成这两个文件,不需要自己定义对应的类型
- 选择Category/Extension,在编译时只会默认生成
Robot+CoreDataProperties
文件,需要手动创建Robot+CoreDataClass
定义该类型
Q&A 如果不是选中Class Definition,选中了Manual/None,怎么手动创建对应Model类的文件?
A: Xcode有配置的选项 👇
就会生成两个文件 👇
image.png
如何创建Model,并保存在CoreData?
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let robotEntity = NSEntityDescription.entity(forEntityName: "Robot", in: context)
let robot = Robot(entity: robotEntity!, insertInto: context)
robot.id = 12138
robot.name = "I'm a robot!"
let robotArmEntity = NSEntityDescription.entity(forEntityName: "RobotArm", in: context)
let robotArm = RobotArm(entity: robotArmEntity!, insertInto: context)
robotArm.id = 555
robotArm.numberOfFingers = 10
robot.arm = robotArm
do {
try context.save()
} catch {
print("Failed saving")
}
print(NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) )
}
}
怎么取出已经保存的数据?
- 生成的Robot类里面已经生成了创建fetchRequest方法,可以直接拿到request
- sort 属性是可以对结果进行排序
// Fetching models from CoreData
do {
let robotsRequest: NSFetchRequest<Robot> = Robot.fetchRequest()
let sort = NSSortDescriptor(key: "id", ascending: true)
robotsRequest.sortDescriptors = [sort]
let robots = try context.fetch(robotsRequest)
print(robots)
} catch {
print("Failed fetching")
}
完整代码
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let robotEntity = NSEntityDescription.entity(forEntityName: "Robot", in: context)
let robot = Robot(entity: robotEntity!, insertInto: context)
robot.id = 12138
robot.name = "I'm a robot!"
let robot1 = Robot(entity: robotEntity!, insertInto: context)
robot1.id = 110
robot1.name = "I'm a robot1 !"
let robotArmEntity = NSEntityDescription.entity(forEntityName: "RobotArm", in: context)
let robotArm = RobotArm(entity: robotArmEntity!, insertInto: context)
robotArm.id = 555
robotArm.numberOfFingers = 10
robot.arm = robotArm
do {
try context.save()
} catch {
print("Failed saving")
}
print(NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) )
// Fetching models from CoreData
do {
let robotsRequest: NSFetchRequest<Robot> = Robot.fetchRequest()
let sort = NSSortDescriptor(key: "id", ascending: true)
robotsRequest.sortDescriptors = [sort]
let robots = try context.fetch(robotsRequest)
print(robots)
} catch {
print("Failed fetching")
}
}
}
按照输出结果可以得到顺序是 Robot 1, 然后才是Robot
如何进行debug?
上面用request去获取数据是其中一种方式,那如果获取不到数据,到底是保存出了问题还是获取出了问题,怎么判断是不是保存的时候出了问题?
首先要拿到sqlite的路径
NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
- 在输出的路径下找到sqlite文件
image.png
- 可以用 DB Brower for SQLite 软件打开,软件下载 【传送门🚪】
打开可以看到数据库里面有几个表,忽略Z
的前缀,可以看到Robot 和 RobotArm 表,打开就可以看到数据是否保存。
image.png
id / arm / name 属性已经保存了数据,ZARM数据是 1
,就是指向另外一张表ZROBOT 的对象1
.
Robot 表
RobotArm 表 image.png
其他内容:
关于继承关系
关于更新已有Model属性
- 添加一个Model Version
- 更新model
- 设置current version
image.png
这个时候如果更新的Model类的Codegen Options选项是Class Definition
或者Category/Extension
, 则不需要去更新什么文件;
如果是Manual/None
, 并且文件中没有其他的逻辑,可以删除了,重新再创建一次,或者直接添加属性在Robot+CoreDataProperties
文件。
网友评论