在点击一个按钮,我试图下载一个新的随机图像和更新视图。当应用程序加载时,它会显示下载的图像。当单击按钮时,图像似乎是下载的,但是视图从未更新过,并显示了place图像。我是不是漏掉了什么,有什么想法吗?这是一个简化的版本。
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
}
}
}
发布于 2019-07-13 19:36:10
这个问题似乎与ContentView
和ImageURL
之间的某种丢失的同步有关(在按钮单击事件之后发生)。
一个可能的解决办法是使ImageURL
成为ContentView
的一个@State
属性。
之后,在按钮单击事件的范围内,我们可以调用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
struct ContentView : View {
@State var url: String = "https://robohash.org/random.png"
@State var image: URLImage = URLImage()
var body: some View {
VStack {
Button(action: {
self.url = "https://robohash.org/\(Int.random(in: 0 ..< 10)).png"
self.image.imageLoader.load(url: URL(string: self.url)!)
}) {
Text("Get Random Robot Image")
}
image
}
}
}
无论如何,我会尝试调查这个问题,如果我知道一些新的东西,我会修改我的答案。
https://stackoverflow.com/questions/57008629
复制相似问题