【发布时间】:2021-05-09 18:26:01
【问题描述】:
我遇到了这种相当常见的情况,List 将来自@ObservedObject 数据存储的一些项目显示为NavigationLinks。
在选择NavigationLink 时,会显示一个DetailView。这个视图有一个简单的 Toggle 连接到其 ViewModel 类上的 @Published 变量。
当 DetailView 出现 (onAppear:) 时,它的 View Model 将控制 Toggle 的已发布 var 设置为 true 并触发一个异步请求,该请求将更新 主数据存储,导致上一个屏幕中的List也更新。
问题在于,当这种情况发生时(List 是从 Detail View 中触发的操作中重新加载),DetailViewModel 的多个实例似乎被保留,并且 DetailView 开始从错误的发布者接收事件>.
在第一次到达详细信息屏幕时,行为是正确的(如下面的代码所示),切换设置为 true 并且 商店 更新,但是,在导航回到List,然后再回到另一个DetailView,在出现时切换设置为true,但这次当重新加载store的代码执行时,切换设置回false .
我的理解是,当重新加载 List 并创建新的 DetailView 和 ViewModel(作为 NavigationLink 的目标)时,来自控制 Toggle 的 isOn 变量的初始值(即false) 以某种方式触发了对当前显示屏幕的Toggle 的更新。
我错过了什么吗?
import SwiftUI
import Combine
class Store: ObservableObject {
static var shared: Store = .init()
@Published var items = ["one", "two"]
private init() { }
}
struct ContentView: View {
@ObservedObject var store = Store.shared
var body: some View {
NavigationView {
List(store.items, id: \.self) { item in
NavigationLink(item, destination: ItemDetailView())
}
}
}
}
struct ItemDetailView: View {
@ObservedObject var viewModel = ItemDetailViewModel()
var body: some View {
VStack {
Toggle("A toggle", isOn: $viewModel.isOn)
Text(viewModel.title)
Spacer()
} .onAppear(perform: viewModel.onAppear)
}
}
class ItemDetailViewModel: ObservableObject {
@ObservedObject var store: Store = .shared
@Published var isOn = false
var title: String {
store.items[0]
}
func onAppear() {
isOn = true
asyncOperationThatUpdatesTheStoreData()
}
private func asyncOperationThatUpdatesTheStoreData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
self?.store.items = ["three", "four"]
}
}
}
【问题讨论】: