Swift数据建模和保存不可为 null 的关系

SwiftData Modeling and saving non Nullable Relations

提问人:David Schilling 提问时间:7/4/2023 最后编辑:HangarRashDavid Schilling 更新时间:9/26/2023 访问量:1042

问:

我有以下代码:

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext

    var schoolClass: SchoolClass

    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
            Button("add", action: {
                let schoolClassSubject = SchoolClassSubject(schoolClass: schoolClass)
                schoolClass.schoolClassSubjects.append(schoolClassSubject)
            })
            
        }
        .padding()
    }
}

@Model
class SchoolClass {
    var name: String
    var schoolClassSubjects: [SchoolClassSubject] = []
    
    init(name: String) {
        self.name = name
    }
}

@Model
class SchoolClassSubject {
    var schoolClass: SchoolClass
    
    init(schoolClass: SchoolClass) {
        print("test")
        self.schoolClass = schoolClass
    }
}

schoolClass已保存在 swiftData 中,并作为属性传递给 。ContentView

换行符,但出现以下异常:let schoolClassSubject = SchoolClassSubject(schoolClass: schoolClass)

由于未捕获的异常“NSInvalidArgumentException”而终止应用,原因:“非法尝试在不同上下文中的对象之间建立关系”schoolClass“(源 = <NSManagedObject:0x60000214cc30>(实体:SchoolClassSubject;id:0x60000024ebe0 x-coredata:///SchoolClassSubject/t186670BB-357C-400C-8D6F-178BEB8F4B473;数据:{ schoolClass = nil;}) ,目标 = <NSManagedObject:0x60000214cd70>(实体:SchoolClass;id:0x600000276740 x-coredata:学校班级/t186670BB-357C-400C-8D6F-178BEB8F4B472;data: { name = test; schoolClassSubjects = ( ); }))'第一次抛出呼叫

如果我将我的模型更改为:

@Model
class SchoolClassSubject {
    var schoolClass: SchoolClass? = nil
    init() {
    }
}

我的保存代码如下:

let schoolClassSubject = SchoolClassSubject()
modelContext.insert(schoolClassSubject)
schoolClassSubject.schoolClass = schoolClass
schoolClass.schoolClassSubjects.append(schoolClassSubject)

但我不想做可选,因为它不是现实。我怎样才能使它不是可选的,并且仍然保存它而不会出现给定的错误?schoolClassschoolClassSubject

SwiftUI Swift-Data

评论

0赞 JimmyJammed 10/6/2023
运气好吗?同样的问题,我有两个模型,其中一个需要另一个模型的非可选(必需)属性。

答:

3赞 Joakim Danielson 7/4/2023 #1

这个答案是使用 Xcode 15.0 beta 2 编写的,在未来的版本中,我认为这个答案将变得无关紧要,我们可以更轻松地处理这个问题

再一次,您必须使用注释才能使关系正常工作,一旦您拥有该注释,SwiftData 将为您处理它们。@Relationship

因此,您不应在模型的任何方法中包含任何关系属性。init

因此,将 init 更改为SchoolClassSubject

init() {}

(我不知道我们在这里需要一个空的 init 是一个错误,还是这只是一个奇怪的情况,因为没有其他属性)

然后将按钮操作中的代码更改为

let schoolClassSubject = SchoolClassSubject()
modelContext.insert(schoolClassSubject)
schoolClassSubject.schoolClass = schoolClass

为了澄清上面的代码:

  • 首先创建模型对象的实例
  • 然后将对象插入到模型上下文中
  • 最后,将任何关系属性分配给您的对象
  • (保存)

评论

0赞 David Schilling 7/4/2023
如果 in 是可选的,这仅适用于我。但我希望它不是问题中所说的可选的。schoolClassschoolClassSubject
0赞 Joakim Danielson 7/4/2023
我使用的模型与您完全相同,没有什么是可选的。
0赞 Joakim Danielson 7/4/2023
我今天实际上在我自己的代码中遇到了完全相同的问题,解决方案与此答案中所述完全相同。
0赞 Thecafremo 8/29/2023
@JoakimDanielson – 您如何在最新的测试版 (7) 上解决它?因为这似乎不再起作用了。
0赞 Joakim Danielson 8/29/2023
@Thecafremo 是的,看起来像这个问题。我没有时间研究它,而不是评论中提到的
0赞 Paragate 9/26/2023 #2
Think it depends on how to keep track of your RelationShip.
If One To Many Relation.

SchoolClass kan have many SchoolClassSubject
SchoolClassSubject only belong to one SchoolClass

@Model
class SchoolClass {
    var name: String
     @Relationship(deleteRule: .cascade)
     var schoolClassSubjects =[SchoolClassSubject]() 
    init(name: String) {
        self.name = name
    }
}

@Model
class SchoolClassSubject {
    var schoolClassSubject: String

    @Relationship(inverse: \SchoolClass.schoolClassSubjects)
    var schoolClass: SchoolClass?  // ? meaning of optional 


    init(schoolClassSubject: String) {
        //print("test")
        self.schoolClassSubject = schoolClassSubject
    }
}
// then in WindowGroup you have to have
 .modelContainer(for: SchoolClass .self

//In Views
 @Environment(\.modelContext) private var context
    
    let schoolClass: SchoolClass

// You can do in Views save func
let transaction = SchoolClassSubject(schoolClassSubject: "String here..")
       

transaction.schoolClass = schoolClass

评论

0赞 inder_gt 10/7/2023
将其分解为单独的代码段可能会有所帮助,以便将属于单个文件中的代码分组在一起,并与其他有用的代码行分开。