我在将异步函数运行在后台线程方面遇到了麻烦(以防止阻塞主线程)。
下面是一个需要大约5秒钟来运行的方法。
从我所学到的知识来看,似乎只需使函数async
并在函数调用上标记await
就足够了。但它并没有按预期工作,仍然会冻结UI。
编辑 由于Swift 5.5并发可以替换DispatchQueue,我正在尝试找到一种仅使用Async / Await实现此目的的方法。
编辑_2 我确实尝试过删除@MainActor包装器,但它仍然似乎在主线程上运行。
NumberManager.swift
@MainActor class NumberManager: ObservableObject {
@Published var numbers: [Double]?
func generateNumbers() async {
var numbers = [Double]()
numbers = (1...10_000_000).map { _ in Double.random(in: -10...10) }
self.numbers = numbers
// takes about 5 seconds to run...
} }
ContentView
struct ContentView: View {
@StateObject private var numberManager = NumberManager()
var body: some View{
TabView{
VStack{
DetailView(text: isNumbersValid ? "First number is: \(numberManager.numbers![0])" : nil)
.onAppear() {
Task {
// Runs in the main thread, freezing up the UI until it completes.
await numberManager.generateNumbers()
}
}
}
.tabItem {
Label("One", systemImage: "list.dash")
}
Text("Hello")
.tabItem {
Label("Two", systemImage: "square.and.pencil")
}
}
}
var isNumbersValid: Bool{
numberManager.numbers != nil && numberManager.numbers?.count != 0
} }
我尝试过的方法...
我尝试了几种方法,但唯一使它在后台运行的方式是更改函数如下。但我知道除非绝对必要,否则应避免使用Task.detached,并且我认为这不是正确的用例。
func generateNumbers() async {
Task.detached {
var numbers = [Double]()
numbers = (1...10_000_000).map { _ in Double.random(in: -10...10) }
await MainActor.run { [numbers] in
self.numbers = numbers
}
}
@MainActor
标记了你的类 - 所以它仍然在主队列上执行。移除它或者,正如你发现的那样,使用结构化并发将任务从主队列中分离出来。 - Paulw11