我目前有一个应用程序正在从API提取数据,在根视图(称为Home)中,一切正常,在第二个视图(称为User View)中,一切正常,但现在在第三个视图(团队视图),仅此视图的ObservedObject
不起作用。
最奇怪的是,如果用户直接导航到“团队视图”,那么一切都会按预期进行。
每个视图都有自己的ObservedObject
,要加载的数据仅属于该视图
每个视图之间的导航由NavigationLink
这里是我如何进行加载和导航的一个例子。
struct HomeView: View {
@ObservedObject var viewModel = HomeViewModel()
var body: some View {
VStack {
NavigationLink(destination: UserView(userId: viewModel.userId))
NavigationLink(destination: TeamView(teamId: viewModel.teamId))
}
}
}
struct TeamView: View {
@ObservedObject var viewModel = TeamViewModel()
@State var teamId: String = ""
var body: some View {
Text(viewModel.name)
.onAppear() { viewModel.loadData(id: teamId) }
}
}
struct UserView: View {
@ObservedObject var viewModel = UserViewModel()
@State var userId: String = ""
var body: some View {
VStack {
Text(viewModel.name)
NavigationLink(destination: TeamView(teamId: viewModel.teamId))
}
.onAppear() { viewModel.loadData(id: userId) }
}
}
从示例中您可以看到,用于加载数据的函数在视图模型中,并在视图出现时加载。
一切正常,但是当我到达堆栈的第3级时,数据不会在视图中更新。我以为可能是线程,但是提取完成后我正在使用DispatchQueue.main.async
。
模型上所有必需的变量都标记为@Published
总而言之,以下流程起作用
HomeView -> TeamView
HomeView -> UserView
但是在最后一个视图上,它确实加载了数据,但没有更新视图
HomeView -> UserView -> TeamView
答案 0 :(得分:1)
我复制了您的代码行为,该问题是由于快速导航引起的。这是怎么回事
如果愿意的话
HomeView [tap] -> UserView -> [wait for user loaded] -> TeamView // no issue
但是你可以
HomeView [tap] -> UserView [tap] -> TeamView // got defect
缺陷在于,因为UserView
在加载数据时在后台更新,所以body
被重建,链接被重新创建,TeamView
被重建,而.onAppear
被重建不会被调用,因为这种视图已经出现在屏幕上了。
(我不确定这是否是SwiftUI错误,因为这种行为有逻辑)。
因此,这是此情况的解决方案。经过Xcode 11.5b的测试。
struct TeamView: View {
@ObservedObject var viewModel = TeamViewModel()
var teamId: String // << state is not needed
init(teamId: String) {
self.teamId = teamId
viewModel.loadData(id: teamId) // initiate load here !!
}
var body: some View {
Text(viewModel.name)
}
}
struct UserView: View {
@ObservedObject var viewModel = UserViewModel()
@State var userId: String = ""
var body: some View {
VStack {
Text(viewModel.name)
// used DeferView to avoid in-advance constructions
NavigationLink(destination: DeferView { TeamView(teamId: viewModel.teamId) })
}
.onAppear() { viewModel.loadData(id: userId) }
}
}
DeferView
来自我的帖子this。