asynchronous - 如何链接 ObservableObject?

标签 asynchronous swiftui combine

我有一个可以保存图像的游戏对象。每当找到游戏的图像 URL 时,就应该创建一个新的 GameImage 对象实例。然后它将获取图像并填充 UIImage 属性。发生这种情况时,应更新 UI 以显示图像。

class Game: ObservableObject {
    @Published var image: GameImage?
} 

class GameImage: ObservableObject {
    let url: URL
    @Published var image: UIImage?
    
    private var cancellable: AnyCancellable?
    
    init(url: URL) {
        self.url = url
    }
    
    func fetch() {
        self.cancellable = URLSession.shared.dataTaskPublisher(for: self.url)
            .map { UIImage(data: $0.data) }
            .replaceError(with: nil)
            .receive(on: DispatchQueue.main)
            .sink(receiveValue: { [weak self] (image) in
                guard let self = self else { return }
                self.image = image
                print(self.url)
                print(self.image)
            })
    }
    
    func cancel() {
        cancellable?.cancel()
    }
    
    deinit {
        cancel()
    }
}

struct ContentView: View {
    
    @StateObject var game = Game()

    var body: some View {
        VStack {
            if let image = game.image?.image {
                Image(uiImage: image)
            } else {
                Text("No image.")
            }
        }
        .onAppear(perform: {
            guard let gameImageURL = URL(string: "https://cf.geekdo-images.com/itemrep/img/oVEpcbtyWkJjIjk1peTJo6hI1yk=/fit-in/246x300/pic4884996.jpg") else { return }
            game.image = GameImage(url: gameImageURL)
            game.image!.fetch()
        })
    }
}

问题是。提取完成后,调试控制台将显示该图像包含一个 UIImage。但是,UI 不会更新以显示图像。我在这里缺少什么?

最佳答案

有比链接 ObservableObject 更简单的解决方案,只需将依赖部分分离到独立的 subview 中......所有的都会自动工作。

这是可能的方法。已使用 Xcode 12/iOS 14 进行测试。

struct ContentView: View {

    @StateObject var game = Game()

    var body: some View {
        VStack {
            if nil != game.image {
                GameImageView(vm: game.image!)
            }
        }
        .onAppear(perform: {
            guard let gameImageURL = URL(string: "https://cf.geekdo-images.com/itemrep/img/oVEpcbtyWkJjIjk1peTJo6hI1yk=/fit-in/246x300/pic4884996.jpg") else { return }
            game.image = GameImage(url: gameImageURL)
            game.image!.fetch()
        })
    }
}

struct GameImageView: View {
    @ObservedObject var vm: GameImage

    var body: some View {
        if let image = vm.image {
            Image(uiImage: image)
        } else {
            Text("No image.")
        }
    }
}

关于asynchronous - 如何链接 ObservableObject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63426017/

相关文章:

带有 Slack 机器人的 Python asyncio

swift - 有什么方法可以用 swiftUI 获取 gif 作为背景吗?

swift - 表单中各部分之间的间距

ios - SwiftUI - 按下按钮时如何更改所有其他按钮的颜色?

ios - subview 模型的计算属性不会更新父 View 模型的 @ObservedObject

observable - 如何设置相同类型的多个环境对象

c# - 异步调用并行 for 循环

javascript - 异步: Connecting to MongoDB after the server started

c# - 关于异步返回类型

快速组合 : Using timer publisher in an observable object