当我们创建一个新的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”,这使我们可以完全控制类的生成方式。
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
在那小段代码中,您可以看到三件事:
- 这就是我们的可选问题的来源。
-
year
不是可选的,这意味着Core Data将为我们采用默认值。 - 它在所有三个属性上使用
@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的可选值,如果要更改默认值,可以在一个文件中完成。
为什么 ForEach 可以使用 .self ? | Hacking with iOS: SwiftUI Edition | 有条件地保存 NSManagedObjectContext |
---|
赏我一个赞吧~~~
网友评论