在我的应用程序(使用 SwiftUI、SwiftData 和 CloudKit)中,我有以下类和枚举:
@Model
class CategoryType
{
var name: String = ""
var parameterType: CategoryTypeParameterType = CategoryTypeParameterType.none
init(name: String, parameterType: CategoryTypeParameterType)
{
self.name = name
self.parameterType = parameterType
}
}
enum CategoryTypeParameterType: Codable, CaseIterable, Hashable
{
case none
case number(number: UInt)
case range(range: ClosedRange<UInt>)
var name: String
{
switch self
{
case .none:
return "None"
case .number:
return "Number"
case .range:
return "Range"
}
}
static var allCases: [CategoryTypeParameterType]
{
return [.none,
.number(number: 1),
.range(range: 1...10)]
}
}
简单地创建一个具有
CategoryType
且值为 parameterType
的 CategoryTypeParameterType.range
对象会导致程序崩溃,结果如下:
Thread 1: "[<__SwiftValue 0x301467570> valueForUndefinedKey:]: this class is not key value coding-compliant for the key lowerBound.
我正在像这样创建对象:
let book = ProjectType(name: "Book")
self.modelContext.insert(projectType)
book.categoryTypes?.append(CategoryType(name: "Pages", parameterType: CategoryTypeParameterType.range(range: 1...10)))
这是
ProjectType
类供参考:
@Model
class ProjectType
{
var name: String = ""
@Relationship(deleteRule: .cascade, inverse: \CategoryType.projectTypes) var categoryTypes: [CategoryType]?
var createdDate: Date = Date.now
init(name: String)
{
self.name = name
self.categoryTypes = []
}
}
为什么这不起作用?
发生的情况是,SwiftData 创建一个 SQL 表,其中包含单独的数字列以及范围的下限和上限。但即使它本身创建了这样的表,它在尝试保存对象时也无法正确使用它,所以这显然是这里涉及的一些错误。
所以我对此没有解决方案,只能暂时使用一个解决方法。解决方案与 SwiftData 和 Core Data 中其他情况下有时使用的模式相同,即存储基本类型,然后使用该类型的计算属性。
所以首先我们将类型为
Data
的私有属性添加到 CategoryType
private var parameterTypeData: Data
然后是使用 json 编码和解码在 enum 和
Data
之间进行转换的计算属性
var parameterType: CategoryTypeParameterType {
get { try! JSONDecoder().decode(CategoryTypeParameterType.self, from: parameterTypeData) }
set { parameterTypeData = try! JSONEncoder().encode(newValue) }
}
我还更改了 init,以便我们为参数提供默认值,并且我们需要单独对该参数进行编码。
init(name: String, parameterType: CategoryTypeParameterType = .none) {
self.name = name
parameterTypeData = try! JSONEncoder().encode(parameterType)
}
请注意,我在编码和解码时使用
try!
,它应该可以正常工作,因为 parameterTypeData
属性是私有的,因此除了枚举中存在的值之外,不能设置其他值,但如果您愿意,您可能需要更改它。