以下是我的观点:
import SwiftUI
struct ContentView: View {
private let weatherLoader = WeatherLoader()
@State private var temperature = ""
@State private var pressure = ""
@State private var humidity = ""
@State private var tickmark = ""
@State private var refreshable = true
var body: some View {
GeometryReader { metrics in
VStack(spacing: 0) {
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
GridRow {
Text("Температура")
.frame(width: metrics.size.width/2)
Text("\(temperature) °C")
.frame(width: metrics.size.width/2)
}.frame(height: metrics.size.height*0.8*0.25)
GridRow {
Text("Давление")
.frame(width: metrics.size.width/2)
Text("\(pressure) мм рт ст")
.frame(width: metrics.size.width/2)
}.frame(height: metrics.size.height*0.8*0.25)
GridRow {
Text("Влажность")
.frame(width: metrics.size.width/2)
Text("\(humidity) %")
.frame(width: metrics.size.width/2)
}.frame(height: metrics.size.height*0.8*0.25)
GridRow {
Text("Дата обновления")
.frame(width: metrics.size.width/2)
Text("\(tickmark)")
.frame(width: metrics.size.width/2)
}.frame(height: metrics.size.height*0.8*0.25)
}.frame(height: metrics.size.height*0.8)
Button("Обновить") {
refreshable = false
print("handler : \(Thread.current)")
Task.detached {
print("task : \(Thread.current)")
let result = await weatherLoader.loadWeather()
await MainActor.run {
print("main actor: \(Thread.current)")
switch result {
case .success(let item):
temperature = item.temperature
pressure = item.pressure
humidity = item.humidity
tickmark = item.date
case .failure:
temperature = ""
pressure = ""
humidity = ""
tickmark = ""
}
refreshable = true
}
}
}
.disabled(!refreshable)
.padding()
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.frame(width: 320, height: 240)
}
}
问题是,从异步上下文中更新@State
个变量的正确方式是什么?我看到如果我go 掉MainActor.run
没有失败,但是在处理UIKit
时,我们必须从主线程调用这个更新.这里有什么不同吗?我还了解到,任务继承了MainActor
上下文,因此我放置了Task.detached
以确保它是Main之外的另一个线程.有谁能给我讲清楚吗?