我认为我对SwiftUI的工作原理有了很好的理解.但有时候还是有一些事情让我困惑,特别是当涉及国家的时候.以下是一些基本代码.
首先,我有一个模型.
struct Item : Equatable {
let id = UUID()
let name: String
}
一个ViewModel
@Observable
final class ContentViewModel {
var items = [
Item(name: "test1"),
Item(name: "test2"),
Item(name: "test3")
]
func mark(item: Item, wrong: Bool) {
//deal with right or wrong answer
items.removeAll {
$0 == item
}
}
}
还有一些观点
struct ContentView: View {
let viewModel = ContentViewModel()
var body: some View {
if let item = viewModel.items.first {
BackwardableView(item) {
QuizView(item, fallback: $0)
}
.environment(viewModel)
}
}
}
struct QuizView : View {
private let item: Item
@Binding private var fallback: Bool
@Environment(ContentViewModel.self) private var viewModel
init(_ item: Item, fallback: Binding<Bool>) {
self.item = item
self._fallback = fallback
}
var body: some View {
VStack {
Text("Quiz \(item.name)")
Button("Wrong Answer") {
fallback = true
}
Button("Correct Answer") {
viewModel.mark(item: item, wrong: false)
}
}
}
}
struct FallbackView : View {
private let item: Item
@Environment(ContentViewModel.self) private var viewModel
init(_ item: Item) {
self.item = item
}
var body: some View {
Text("Fallback \(item.name)")
.toolbar {
Button("Next") {
viewModel.mark(item: item, wrong: true)
}
}
}
}
struct BackwardableView<Content: View> : View {
private let item: Item
private let content: (Binding<Bool>) -> Content
@Environment(ContentViewModel.self) private var viewModel
@State private var backward = false
init(_ item: Item, content: @escaping (Binding<Bool>) -> Content) {
self.item = item
self.content = content
}
var body: some View {
Group {
if backward {
FallbackView(item)
} else {
content($backward)
}
}
.id(item.id)
// .onChange(of: item) { oldValue, newValue in
// if oldValue == newValue {
// return
// }
// backward = false
// }
}
}
问题出现在最后一个视图中.每当QuizView触发回退时,它应该切换到回退视图并执行一些回退操作.在这个模拟代码中,它简单地要求viewModel删除第一个项目并跳转到下一个项目.然而,BackwardableView似乎保留了下一个项目的"向后状态",这是不合逻辑的.
我试着添加一个显式的id来区分这个视图是全新的.这个技巧通常有效,因为我假设它允许SwiftUI将其识别为一个不同的视图.但在这种情况下它并不有效.添加onChange修饰符解决了这个问题.虽然我理解这种方法是可行的,但我仍然对视图(假定它是一个具有不可变属性(包括项)的 struct )如何明显改变感到困惑.