在一个视图中,我想等待一系列异步调用完成加载,然后重定向到另一个屏幕。不幸的是,我看到代码在后面运行(JSON数据被加载),但一旦完成,它就不重定向到新视图。
以下是我的看法:
struct loadingView: View {
@ObservedObject var dataLoader: DataLoader = DataLoader()
@State var isLoaded: Bool = false
var body: some View {
VStack {
Text("Loading \(isLoaded)")
}
}
.task {
await self.dataloader.loadJSONData(isLoaded: $isLoaded)
MainScreen()
}
}
...和DataLoader类:
@MainActor DataLoader: NSObject, ObservableObject {
func loadJSONData(isLoaded: Binding<Bool>) {
await doLoadData()
isLoaded.wrappedValue = True
}
func doLoadData() async {
/* do data load */
/* This code works */
}
}
3条答案
按热度按时间vh0rcniy1#
这里的“重定向”并没有什么意义。你真的希望用户能够导航回加载屏幕吗?也许你把它想象成一个网页,但SwiftUI不是这样的。你真正想做的是在加载时显示一个东西,而在加载时显示另一个东西。这只是
if
,而不是“重定向”。相反,考虑下面的模式,创建这样的LoadingView(从我的一些个人代码中提取):
它不需要重定向,只是在不同的状态下显示不同的内容(显然,
Text
视图可以被更有趣的东西取代)。然后要使用它,将它嵌入到另一个视图中。在我的个人代码中,它包括这样的视图:
那么LoadedDailyView就是“真实的的”视图,它由
DailyModel.init
创建的完全填充的model
处理(抛出,异步初始化)。oxf4rvwz2#
您可以尝试这种方法,使用
NavigationStack
和NavigationPath
到Redirecting after task w/ Await completes
。下面是我用来测试答案的代码:
如果你需要iOS15或更早版本,那么使用
NavigationView
:如果
loadingView
的唯一目的是显示“loading”消息,然后在加载数据后显示MainScreen
,则可以使用以下方法(使用简单的开关):eufgjt7s3#
使用
@StateObject
而不是@ObservedObject
。使用@Published
而不是尝试传递绑定到对象(这是一个错误,因为绑定只是一对get和set闭包,如果LoadingView
被重新初始化,它们将过期),使用Group
和if
来有条件地显示View
,例如:DataLoader
不应是@MainActor
,因为您希望它在后台线程上运行。一旦异步工作完成,请在子任务上改用@MainActor
,例如这个模式在苹果的教程中显示,
PandaCollectionFetcher.swift
复制如下: