簡體   English   中英

在 SwiftUI 的異步塊中改變 @State 變量是否安全?

[英]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)))
    }
}

我使內部視圖( IP類型)進行相應交換的唯一方法是從異步塊內部分配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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM