单击按钮后,我试图下载一个新的随机图像并更新视图。应用加载后会显示下载的图片。单击该按钮时,图像似乎已下载,但视图从未更新,并显示占位符图像。我在这里想念什么吗?这是简化版。
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
}
}
}
答案 0 :(得分:1)
该问题似乎与ContentView
和ImageURL
之间的某种同步丢失有关(在按钮单击事件之后发生)。
一个可能的解决方法是将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返回图像。