下载图像后在SwiftUI中更新图像视图

时间:2019-07-12 14:05:43

标签: swift swiftui

单击按钮后,我试图下载一个新的随机图像并更新视图。应用加载后会显示下载的图片。单击该按钮时,图像似乎已下载,但视图从未更新,并显示占位符图像。我在这里想念什么吗?这是简化版。

import SwiftUI

struct ContentView : View {

    @State var url = "https://robohash.org/random.png"

    var body: some View {
        VStack {
            Button(action: {
                self.url = "https://robohash.org/\(Int.random(in:0 ..< 10)).png"
            }) {
                Text("Get Random Robot Image")
            }
            URLImage(url: url)
        }

    }
}
class ImageLoader: BindableObject {

    var downloadedImage: UIImage?
    let didChange = PassthroughSubject<ImageLoader?, Never>()

    func load(url: String) {

        guard let imageUrl = URL(string: url) else {
            fatalError("Image URL is not correct")
        }

        URLSession.shared.dataTask(with: imageUrl) { data, response, error in
            guard let data = data, error == nil else {
                DispatchQueue.main.async {
                    self.didChange.send(nil)
                }
                return
            }

            self.downloadedImage = UIImage(data: data)
            DispatchQueue.main.async {
                print("downloaded image")
                self.didChange.send(self)
            }
        }.resume()
    }
}

import SwiftUI

struct URLImage : View {

    @ObjectBinding private var imageLoader = ImageLoader()
    var placeholder: Image

    init(url: String, placeholder: Image = Image(systemName: "photo")) {
        self.placeholder = placeholder
        self.imageLoader.load(url: url)
    }

    var body: some View {
        if let uiImage = self.imageLoader.downloadedImage {
            print("return downloaded image")
            return Image(uiImage: uiImage)
        } else {
            return placeholder
        }
    }
}

2 个答案:

答案 0 :(得分:1)

该问题似乎与ContentViewImageURL之间的某种同步丢失有关(在按钮单击事件之后发生)。

一个可能的解决方法是将ImageURL的{​​{1}}属性设置为@State

此后,在按钮单击事件的范围内,我们可以调用ContentView方法。图像下载结束后,发布者(image.imageLoader.load(url: ))将通知didChange,然后将更改正确传播到ImageURL

ContentView

import SwiftUI import Combine enum ImageURLError: Error { case dataIsNotAnImage } class ImageLoader: BindableObject { /* init(url: URL) { self.url = url } private let url: URL */ let id: String = UUID().uuidString var didChange = PassthroughSubject<Void, Never>() var image: UIImage? { didSet { DispatchQueue.main.async { self.didChange.send() } } } func load(url: URL) { print(#function) self.image = nil URLSession.shared.dataTask(with: url) { (data, res, error) in guard error == nil else { return } guard let data = data, let image = UIImage(data: data) else { return } self.image = image }.resume() } } 视图:

URLImage

struct URLImage : View { init() { self.placeholder = Image(systemName: "photo") self.imageLoader = ImageLoader() } @ObjectBinding var imageLoader: ImageLoader var placeholder: Image var body: some View { imageLoader.image == nil ? placeholder : Image(uiImage: imageLoader.image!) } }

ContentView

无论如何,我将尝试调查问题,如果我知道新知识,我将修改我的答案。

答案 1 :(得分:0)

我认为您的问题是您更新了downloadedImage,但实际上并未更新placeholder。 也许也尝试从“绑定”的ImageLoader返回图像。