0

我有以下View在内部使用 async/await 的结构 ()。

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从线程/线程安全的角度来看,这是一种安全的做法,还是我必须以其他方式实现它?

4

1 回答 1

2

从主线程之外的另一个线程更新 UI 数据是不安全的。而且 Swift 的并发模型不保证异步代码运行的线程。

所以你的问题的答案是一个很大的否定。

您将需要在主线程上调度属性更新。主要演员是这样做的推荐方式。

只需为此添加一个新功能

@MainActor func updateImage(to newImage: UIImage) {
    image = newImage
}

,并从异步任务中调用它:

await updateImage(to: uiImage)
于 2021-06-19T20:37:18.250 回答