我有 2 个简单模型,具有 1 对多关系。
CarMake
可以有多个CarModels
,但一个CarModel只能属于一个CarMake。非常简单。
@Model
final class CarModel {
var name: String
var make: CarMake
init(name: String, make: CarMake) {
self.name = name
self.make = make
}
}
@Model
final class CarMake {
var name: String
@Relationship(inverse: \CarModel.make) var models: [CarModel] = []
init(name: String) {
self.name = name
}
}
我创建了一个视图,它将列出所有
CarMakes
,另一个视图将列出 CarModels
的关系属性中的 CarMake
,并且还允许我将新的 CarModel
添加到 CarMake
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [CarMake]
@State var count: Int = 1
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
NavigationLink(item.name) {
CarMakeView(make: item)
}
}
}
.toolbar {
Button {
addItem(name: "Car Make \(count)")
count += 1
} label: {
Image(systemName: "plus")
}
}
}
}
private func addItem(name: String) {
let newItem = CarMake(name: name)
modelContext.insert(newItem)
}
}
struct CarMakeView: View {
@Environment(\.modelContext) private var modelContext
@State var count: Int = 1
var make: CarMake
var body: some View {
List {
ForEach(make.models) { item in
Text(item.name)
}
}
.toolbar {
Button {
addItem(name: "Car Model \(count)")
count += 1
} label: {
Image(systemName: "plus")
}
}
}
private func addItem(name: String) {
let newItem = CarModel(name: name, make: make)
modelContext.insert(newItem)
}
}
将新的
CarModel
对象添加到 modelContext,如 private func addItem(name: String)
中所示,不会导致 make.models
(关系)列表更新。
数据已正确添加到数据库中,因为如果我重新启动应用程序,列表将显示之前应用程序运行中添加的所有 CarModels
。更改屏幕并不重要,直到应用程序重新启动后关系才会更新。
有人可以帮我指出我在这段代码中做错了什么吗?
我尝试简单地添加一个与另一个对象有关系的新对象,然后以一对多关系列出所有对象。我希望一旦更新数据库就可以获得数据。
这是 SwiftData 中的某种错误,因为您没有做任何错误的事情。问题是您的
CarMakeView
具有 make
类型的属性 CarMake
但您不是直接更新该属性而是通过关系,这意味着视图看不到任何依赖项正在更新,并且没有理由自行更新。
这就是错误,因为
make
实际上是在添加新汽车模型时更新的,但不知何故,没有正确观察到关系属性的这种变化。
有一些解决方法
如果关系属性是可选的,我使用的方法是将新的 CarModel 对象附加到
make
属性,因为这样我们就直接更新 make
属性
private func addItem(name: String) {
let newItem = CarModel(name: name)
make.models.append(newItem)
}
对于您的情况,我们需要在
CarModel
中将关系属性设为可选,但要使其起作用
@Model
final class CarModel {
var name: String
var make: CarMake?
init(name: String, make: CarMake? = nil) {
self.name = name
self.make = make
}
}
另一个解决方案是出于其他原因进行视图更新,在您的示例中,我只是使用了现有属性
@State var count: Int = 1
并将其添加到文本中的正文中,这将导致视图重绘
var body: some View {
VStack {
Text("\(count)")
List {
ForEach(make.models) { item in
//...