ios - 执行 `await` 后的 Swift 任务和等待/异步队列?

标签 ios swift swiftui async-await

我试图了解调用 Task { ... } 时的规则是什么,并且在该任务中,根据线程调用 await

这个例子有效:

struct TaskTestView: View {
    
    let url = URL(string: "https://www.google.com")!
    @State private var message = "Loading..."

    var body: some View {
        Text(message)
            .task {
                /// on MAIN THREAD
                do {
                    var receivedLines = [String]()
                    for try await line in url.lines {
                 /// on MAIN THREAD
                        receivedLines.append(line)
                        message = "Received \(receivedLines.count) lines"
                    }
                } catch {
                    message = "Failed to load"
                }
            }
    }
}

这不是:

struct TaskTestView: View {

    @StateObject var model = TaskTestViewModel()
    
    var body: some View {
        Text(model.message)
            .task {
                /// - here it is on main thread
                await model.refresh()
                /// - here it is NOT on main thread
                print("after refresh: on main?")
            }
    }
}

class TaskTestViewModel:ObservableObject {
    
    let url = URL(string: "https://www.google.com")!
    @Published private(set) var message = "Loading..."
    
    func refresh() async {
        
        do {
            var receivedLines = [String]() // on main thread
            for try await line in url.lines {
                receivedLines.append(line) // NOT on main thread
                message = "Received \(receivedLines.count) lines"
            }
        } catch {
            message = "Failed to load"
        }
        
    }
    
}
  1. 为什么代码在第一个示例中 for try await line in url.lines { 行之后在主线程上运行?
  2. 为什么代码不在同一行之后但在第二个示例中的主线程上运行?

如果不运行代码并设置断点来检查我所在的线程,我怎么知道这些问题的答案?

显然,这里的主要问题是我想确保更新 main 上的 @State 变量,以便 View 正常工作,但是,如果这个概念不清晰,就很难设计出合适的模式。

最佳答案

关于“延续”将在哪个线程上运行没有明确的规定。 WWDC 2021 视频 Swift concurrency: Behind the scenes讨论延续以及暂停点之后的线程可能与之前的线程有何不同。

尝试使用传统的调试语句或断点对其进行诊断可能会令人沮丧。我遇到过插入几行完全不相关的调试代码会改变连续线程行为的情况。底线是,除非您另有说明,否则可以自由决定延续将在哪个线程上运行,并且有时可能会出乎意料。

但是,如果您想确保您的可观察对象在主线程上更新,您可以使用 @MainActor 限定符:

@MainActor
class TaskTestViewModel: ObservableObject {
    ... 
}

关于ios - 执行 `await` 后的 Swift 任务和等待/异步队列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71149249/

相关文章:

iphone - 在 UITableViewCell 中启用/禁用编辑模式

javascript - 变量似乎没有在移动设备上设置

ios - ScrollView 中最后一个元素的坐标

javascript - 如何使用cocos2d-js加载原生IOS xib?

iphone - 我如何确定我的应用程序何时将在后台终止?

ios - 识别哪个 UISwitch 被点击

swift - 创建后回调: How to run code immediately after ctor?

ios - 通过函数使用Gesture时类型 'any View'不能符合 'View'

json - 如何在 SwiftUI 中访问 json 响应?

swift - 在 SwiftUI 中添加 TotalValue 列表值