为了可以从 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 方法一会儿用到的时候再说。而 titlesummary 则对应之前在 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

如此一来,只要直接给 titlesummary 赋值:

episode.title = "Core data demo II";
episode.summary = "Subclass NSManagedObject."

最后,同样是保存 managedContext,新纪录就写入到 Core Data 了:

CoreDataManager.shared.saveContext(managedContext)

实际上,除了手工创建 NSManagedObject 之外,我们还可以用下面的方法把创建 NSEntityDescriptionNSManagedObject 合并成一步:

let episode = NSEntityDescription.insertNewObject(
  forEntityName: "Episode",
  into: managedContext) as! Episode

当然这两种方法的作用,是完全一样的。一开始我们拆开这个步骤,是为了方便大家理解 Core Data 中的概念。

读取数据

接下来,再来看读取数据。上一节,我们得到了一个用于读取数据的 NSFetchRequest 对象:

let fetchRequest = NSFetchRequest<NSManagedObject>(
  entityName: "Episode")

还记得刚才 Xcode 自动给 Episode 生成了一个 fetchRequest 方法么,它返回一个 NSFetchRequest<Episode> 对象。现在,就可以直接用这个方法取代 NSFetchRequestinit 方法:

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。

所有订阅均支持 12 期免息分期

¥ 59

按月订阅

一个月,观看并下载所有视频内容。初来泊学,这可能是个最好的开始。

开始订阅

¥ 512

按年订阅

一年的时间,让我们一起疯狂地狩猎知识吧。比按月订阅优惠 28%

开始订阅

¥ 1280

泊学终身会员

永久观看和下载所有泊学网站视频,并赠送 100 元商店优惠券。

我要加入
如需帮助,欢迎通过以下方式联系我们