如何在CloudKit中使Range键值兼容?

问题描述 投票:0回答:1

在我的应用程序(使用 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 = []
    }
}

为什么这不起作用?

swiftui range cloudkit swiftdata key-value-coding
1个回答
0
投票

发生的情况是,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
属性是私有的,因此除了枚举中存在的值之外,不能设置其他值,但如果您愿意,您可能需要更改它。

© www.soinside.com 2019 - 2024. All rights reserved.