例如:
var body: some View {
ScrollViewReader(content: { proxy in
/* ... */
}).task {
do {
let url = URL(string: "https://example.com/data.json")!
let (data, _) = try await URLSession.shared.data(from: url)
/* ... */
} catch {
print(error)
}
}
}
.task
修饰符在下面有什么作用?是用于在数据请求解决后存储和恢复程序的状态吗?
Swift 并发世界的关键。
SwiftUI 的
.task
修饰符从周围的函数继承其 actor 上下文。如果您在视图的 body 属性内调用 .task
,异步操作将在主要参与者上运行,因为 View.body
(半秘密地)用 @MainActor
进行注释。但是,如果您从未添加 .task
注释的辅助属性或函数调用 @MainActor
,则异步操作将在协作线程池中运行。
根据苹果文档:
使用此修饰符可以执行异步任务,其生命周期与修改后的视图的生命周期相匹配。如果在 SwiftUI 删除视图或视图更改标识之前任务未完成,SwiftUI 将取消该任务。
在任务中使用
关键字来等待异步调用完成,或等待await
实例的值。例如,您可以修改文本视图以启动从远程资源加载内容的任务:AsyncSequence
let url = URL(string: "https://example.com")!
@State private var message = "Loading..."
var body: some View {
Text(message)
.task {
do {
var receivedLines = [String]()
for try await line in url.lines {
receivedLines.append(line)
message = "Received \(receivedLines.count) lines"
}
} catch {
message = "Failed to load"
}
}
}
此示例使用
lines
方法以异步字符串序列的形式获取存储在指定 URL 的内容。当每个新行到达时,for-await-in 循环的主体将该行存储在字符串数组中,并更新文本视图的内容以报告最新的行数。