[英]Is it safe to mutate @State variables from inside an async block in SwiftUI?
我有以下在內部使用 async/await 的結構 ( View
)。
struct CachedAsyncImage<I: View, P: View>: View {
@State var image: UIImage?
let content: (Image) -> I
let placeholder: () -> P
let url: URL?
public init(
url: URL?,
@ViewBuilder content: @escaping (Image) -> I,
@ViewBuilder placeholder: @escaping () -> P
) {
self.url = url
self.content = content
self.placeholder = placeholder
}
var body: some View {
async {
guard let url = self.url else {
return
}
let session = URLSession.shared
let taskResponse = try? await session.data(from: url, delegate: nil)
guard let imageData = taskResponse?.0,
let uiImage = UIImage(data: imageData) else {
return
}
image = uiImage
}
guard let image = self.image else {
return AnyView(placeholder())
}
return AnyView(content(Image(uiImage: image)))
}
}
我使內部視圖( I
和P
類型)進行相應交換的唯一方法是從異步塊內部分配image
屬性,該屬性必須用@State
屬性包裝器標記。 從線程/線程安全的角度來看,這是一種安全的做法,還是我必須以其他方式實現它?
從主線程之外的另一個線程更新 UI 數據是不安全的。 而 Swift 的並發性 model 並不能保證運行異步代碼的線程。
所以你的問題的答案是一個很大的否定。
您將需要在主線程上分派屬性更新。 而主要演員是推薦的方式來做到這一點。
只需為此添加一個新的 function
@MainActor func updateImage(to newImage: UIImage) {
image = newImage
}
,並從異步任務中調用它:
await updateImage(to: uiImage)
是的(但它應該在 a.task 修飾符中完成,而不是直接在 body 本身中完成)
您可以從任何線程安全地改變 state 屬性。
https://developer.apple.com/documentation/swiftui/state
在 Swift 中,您應該嘗試使用結構等值類型而不是對象的原因之一。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.