SwiftUI Core Data:创建 NSManagedObject 子类

SwiftUI Core Data:创建 NSManagedObject 子类_第1张图片
NSManagedObject - 韦弦zhy

当我们创建一个新的Core Data实体时,Xcode在构建代码时会自动为我们生成一个托管对象类。然后,我们可以在SwiftUI @FetchRequest中使用它在我们的用户界面中显示数据,但是正如您所看到的那样,这很痛苦:要解包的选项很多,因此您需要编写许多分散使用空合运算符才能​​使代码正常工作。

有两种解决方案:快速简便的解决方案有时会出现问题,或者较慢的解决方案从长远来看会更好。

首先,让我们创建一个要使用的实体:打开数据模型并创建一个名为Movie的实体,其属性为:“title” (string), “director” (string), 和 “year” (integer 16)。在离开数据模型编辑器之前,我希望您转到“View”菜单,然后选择 " Inspectors > Show Data Model Inspector",它会在Xcode的右侧弹出一个窗格,其中包含有关您当前选择的内容的更多信息。

当您选择 Movie 时,您会看到该实体的各种数据模型选项,但是我特别希望您看到一个选项:“Codegen”。这控制了Xcode在我们构建项目时如何将实体生成为托管对象类,默认情况下它将是类定义。我想将其更改为“Manual/None”,这使我们可以完全控制类的生成方式。


SwiftUI Core Data:创建 NSManagedObject 子类_第2张图片
Codegen

现在,Xcode不再生成供我们在代码中使用的Movie类,除非实际使用一些实际的Swift代码制作该类,否则我们将无法在代码中使用它。为此,请转到“Editor”菜单,然后选择“Create NSManagedObject Subclass”,确保选择了“CoreDataProject”,然后按Next,然后确保选择了 Movie,然后再次按 Next。系统会询问您Xcode将代码保存在何处,因此请确保选择左侧带有黄色文件夹图标的“CoreDataProject”,然后还要选择CoreDataProject文件夹。准备就绪后,请按创建以完成该过程。

我们只是想让Xcode将其生成的代码转换为我们可以查看和更改的实际Swift文件,尽管请记住,如果更改为我们生成的Xcode文件然后重新生成这些文件,所做的更改将会丢失。

Xcode将为我们生成两个文件,但是我们只关心其中一个:Movie + CoreDataProperties.swift。在其中,您将看到以下三行代码:

@NSManaged public var title: String?
@NSManaged public var director: String?
@NSManaged public var year: Int16

在那小段代码中,您可以看到三件事:

  1. 这就是我们的可选问题的来源。
  2. year不是可选的,这意味着Core Data将为我们采用默认值。
  3. 它在所有三个属性上使用@NSManaged

@NSManaged不是属性包装器——它比SwiftUI中的属性包装器要旧得多。实际上,这揭示了Core Data在内部如何工作的一些信息:它们不是真正存在于类中的作为属性的那些值,而是它们实际上只是在Core Data用于存储其信息的字典中进行读写。当我们读取或写入@NSManaged属性的值时,Core Data会捕获并在内部对其进行处理——与简单的Swift字符串相去甚远。

现在,您可能会查看该代码,并认为“我在那里不希望有可选值”,然后将其更改为:

@NSManaged public var title: String
@NSManaged public var director: String
@NSManaged public var year: Int16

你知道吗?那将绝对有效。您可以使用与以前相同的代码制作Movie对象,使用提取请求查询它们,保存其托管对象上下文,等等,所有这些都没有问题。

但是,您可能会注意到一些奇怪的事情:即使我们的属性不再是可选的,也可以在不提供这些值的情况下创建Movie类的实例。这应该是不可能的:这些属性不是可选的,这意味着它们必须始终具有值,但是我们可以在不使用值的情况下创建它们。

这是@NSManaged魔术中的一小部分的展露——请记住,这些不是真正的属性,因此@NSManaged让我们做不该做的事情。它确实可以正常工作,对于小型的Core Data项目和/或学习者,我认为删除可选项是一个好主意。但是,还有一个更深层次的问题:Core Data 是惰性的。

还记得Swift的 lazy 关键字,以及它如何让我们延迟工作直到真正需要它?除了数据之外,Core Data的功能大致相同:有时看起来有些数据实际上不是已经加载的,因为Core Data试图最大程度地减少其对内存的影响。

我们不需要做任何特殊的工作来处理这些错误,因为一旦我们尝试读取它们,Core Data就会透明地获取真实数据并将其发送回去—— @NSManaged的另一个好处。但是,当我们开始关注Core Data 的属性类型时,就有可能暴露其独特的不足之处。这件事显然无法像Swift所期望的那样起作用,如果我们尝试绕开它,那么我们就会引来很多麻烦——我们的值应该是绝对不会为nil,但却在任何时候都可能突然为nil

相反,您可能需要考虑添加计算属性,以帮助我们安全地访问可选值,同时还允许我们将处理可选值代码全部存储在一个位置。例如,将其添加为Movie的属性可确保我们始终具有有效的标题字符串来使用:

public var wrappedTitle: String {
    title ?? "Unknown Title"
}

这样,整个代码的其余部分就不必担心Core Data的可选值,如果要更改默认值,可以在一个文件中完成。

译自 Creating NSManagedObject subclasses

为什么 ForEach 可以使用 .self ? Hacking with iOS: SwiftUI Edition 有条件地保存 NSManagedObjectContext

赏我一个赞吧~~~

你可能感兴趣的:(SwiftUI Core Data:创建 NSManagedObject 子类)