为了可以从 Core Data 读写数据的时候,直接使用 Swift 属性,而不是 OC 风格的 KVC,我们可以为 core data model 中的每一个 ENTITY 创建一个对应的类型,并且,让这个类型是 NSManagedObject
的派生类。
这个类型,可以在包含 core data model 的项目首次编译的时候,由 Xcode 自动生成,这也是 Xcode 对 model 文件默认的选项。因此,在上一节的例子中,当我们编译执行的时候,其实 Xcode 就已经为 Episode ENTITY 生成了一个叫做 Episode
的类,只是这个类型的定义被 Xcode 隐藏了起来。
我们可以在 main.swift 中通过下面这行代码确认它的存在:
print(type(of: Episode.self))
但显然,这种方式对于初次接触 Core Data 的我们来说,并不是很合适。它隐藏的细节太多了。更好的方式是手工生成这个类型,并且能看到它的具体定义。为此,先选中上一节创建的 CoreData.xcdatamodeld,然后选中要生成类型的 ENTITY,在我们的例子中,就是 Episode。在 Show the Data Model inspector 中,把 Codegen 设置成 Manual/None:

然后,保持 Episode ENTITY 被选中,在菜单中选择 Editor / Create NSManagedObject Subclass...:

接下来,Xcode 会提示我们选择对应的 model 以及 ENTITY:

最后,给生成的文件指定一个路径,点击 Create 按钮就好了。这样在项目中,就会多出来两个文件:
- Episode+CoreDataClass.swift 这里,暂时只包含了和 ENTITY 对应的类型定义:
@objc(Episode)
public class Episode: NSManagedObject {
}
- Episode+CoreDataProperties.swift 这里,则是对应 ENTITY 里表示每个属性的定义:
extension Episode {
@nonobjc public class func fetchRequest()
-> NSFetchRequest<Episode> {
return NSFetchRequest<Episode>(entityName: "Episode")
}
@NSManaged public var title: String?
@NSManaged public var summary: String?
}
其中,fetchRequest
方法一会儿用到的时候再说。而 title
和 summary
则对应之前在 episode ENTITY 中添加的两个属性。它们有 NSManaged
修饰,因此才可以放在 Episode
扩展里,正是这个修饰,定义了从 Core Data 中存取这些属性的方法。
之所以 Core Data 要把类型的定义和属性放在不同的文件里,是因为之后如果我们修改了 Episode ENTITY,再重新生成对应类文件的时候,就只会更新 Episode+CoreDataProperties.swift 的部分了。这样,我们就可以把 Episode
需要的方法添加在 Episode+CoreDataClass.swift 里,即便稍后更新了 ENTITY 的定义,重新生成文件也不会覆盖掉我们自己编写的方法。
通过 Episode 存取数据
接下来,定义好 Episode
之后,如何通过它实际在 Core Data 中存取数据呢?
写入数据
先来看写入,上一节,我们创建了一个用于写入的 NSManagedObject
:
let episode =
NSManagedObject(entity: entity, insertInto: managedContext)
但现在我们知道,和这个 entity
对应的,是 Episode
,于是,我们可以把它强转成 Episode
:
let episode = NSManagedObject(
entity: entity,
insertInto: managedContext) as! Episode
如此一来,只要直接给 title
和 summary
赋值:
episode.title = "Core data demo II";
episode.summary = "Subclass NSManagedObject."
最后,同样是保存 managedContext
,新纪录就写入到 Core Data 了:
CoreDataManager.shared.saveContext(managedContext)
实际上,除了手工创建 NSManagedObject
之外,我们还可以用下面的方法把创建 NSEntityDescription
和 NSManagedObject
合并成一步:
let episode = NSEntityDescription.insertNewObject(
forEntityName: "Episode",
into: managedContext) as! Episode
当然这两种方法的作用,是完全一样的。一开始我们拆开这个步骤,是为了方便大家理解 Core Data 中的概念。
读取数据
接下来,再来看读取数据。上一节,我们得到了一个用于读取数据的 NSFetchRequest
对象:
let fetchRequest = NSFetchRequest<NSManagedObject>(
entityName: "Episode")
还记得刚才 Xcode 自动给 Episode
生成了一个 fetchRequest
方法么,它返回一个 NSFetchRequest<Episode>
对象。现在,就可以直接用这个方法取代 NSFetchRequest
的 init
方法:
let fetchRequest: NSFetchRequest<Episode> = Episode.fetchRequest()
这样,在读取记录的时候,也就可以直接使用 Episode
属性了:
episodes.forEach {
let title = $0.title!
let summary = $0.summary!
print("\(title): \(summary)")
}
现在,重新执行一下,在控制台,就可以看到之前新写入的结果了。
What's next?
以上,就是创建 NSManagedObject
派生类的用法。这是我们通过 Swift 使用 Core Data 的主要方式。至此,我们也就了解了 Core Data 中最基础也最重要的概念和用法。下一节,我们来补充一些在这个学习过程中忽略的东西:如何在多个 ENTITY 之间创建 Relationship。