e45*_*ojn 4 concurrency ios swiftui
当我的内容视图加载并且用户第一次打开应用程序时,我会联系 API。
但是,我不希望这妨碍了主要内容。我收到的数据永远不会更新/影响 UI。所以它应该完全在后台运行。
现在,它运行如下:
struct ContentView: View {
@StateObject var settings = Settings()
var body: some View {
}
.task {
await loadData()
}
func loadData() async {
// Call an api.
// get some data using URLSession
settings.data = data
}
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:[SwiftUI] 不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过像 receive(on:) 这样的运算符)。
我想我明白了:SwiftUI 认为我想要更新 UI 的任务。
为了解决这个问题,我尝试了:
.task {
DispatchQueue.global(qos: .background).async {
await loadData()
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我得到: 无法将类型为 '@Sendable () async -> ()' 的函数传递给需要同步函数类型的参数
在这种情况下我将如何使用调度队列?我只针对 iOS 15+。
使用 Swift Concurrency 系统时,您可以使用Task.detached(...)
构造函数生成非结构化分离任务。该任务将在后台同时运行。如果不需要高优先级执行,您还可以指定任务优先级.background
(相当于 DispatchQueue )。qos
当您尝试运行的异步函数更新触发视图重绘的属性时(settings
声明为 anObservedObject
并且我假设data
是一个Published
属性),因此您必须从主要参与者设置此属性。
为此,您可以执行以下操作:
struct ContentView: View {
@StateObject var settings = Settings()
var body: some View {
// Some view...
}
.task {
await loadData()
}
func loadData() async {
await Task.detached(priority: .background) {
// Call an api.
// Get some data using URLSession
await MainActor.run {
settings.data = data
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
添加到路易斯的回应(回答,因为我还不能发表评论),优先级不是后台运行的内容 - 而是部分detached
。
如果您以优先级运行,.background
它将不会被优先化,因此可能需要更长的时间才能执行。
你可以在后台运行一些东西,但也具有高优先级:Task.detached(priority: .userInitiated) {...}
归档时间: |
|
查看次数: |
5157 次 |
最近记录: |