SwiftUI 无法从下载地址获取图片
Posted
技术标签:
【中文标题】SwiftUI 无法从下载地址获取图片【英文标题】:SwiftUI can't get image from download url 【发布时间】:2020-01-14 18:26:38 【问题描述】:我有以下代码从下载网址加载图像并将其显示为 UIImage。
我希望它可以工作,但不知何故,仅显示占位符图像'ccc'
,而不是下载网址中的实际图像。怎么会这样?
我的网址是从数据库中获取的,看起来像这样:
https://firebasestorage.googleapis.com/v0/b/.../o/P...alt=media&token=...-579f...da
struct ShelterView: View
var title: String
var background: String
var available: Bool
var distance: Double
var gender: String
@ObservedObject private var imageLoader: Loader
init(title: String, background: String, available: Bool, distance: Double, gender: String)
self.title = title
self.background = background
self.available = available
self.distance = distance
self.gender = gender
self.imageLoader = Loader(background)
var image: UIImage?
imageLoader.data.flatMap(UIImage.init)
var body: some View
VStack
VStack(alignment: .leading)
VStack(alignment: .leading, spacing: 0)
Text(title)
.font(Font.custom("Helvetica Now Display Bold", size: 30))
.foregroundColor(.white)
.padding(15)
.lineLimit(2)
HStack(spacing: 25)
IconInfo(image: "bed.double.fill", text: String(available), color: .white)
if gender != ""
IconInfo(image: "person.fill", text: gender, color: .white)
.padding(.leading, 15)
Spacer()
IconInfo(image: "mappin.circle.fill", text: String(distance) + " miles away", color: .white)
.padding(15)
Spacer()
.background(
Image(uiImage: image ?? UIImage(named: "ccc")!) <-- HERE
.brightness(-0.11)
.frame(width: 255, height: 360)
)
.frame(width: 255, height: 360)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
final class Loader: ObservableObject
var task: URLSessionDataTask!
@Published var data: Data? = nil
init(_ urlString: String)
print(urlString)
let url = URL(string: urlString)
task = URLSession.shared.dataTask(with: url!, completionHandler: data, _, _ in
DispatchQueue.main.async
self.data = data
)
task.resume()
deinit
task.cancel()
【问题讨论】:
【参考方案1】:您的图像是一个普通的旧var
,在构建视图时恰好为零。 SwiftUI 只会重建自身以响应@ObservedObject
、@State
或@Binding
的变化,因此将您的图像移动到imageLoader
上的@Published
属性,它将起作用。这是我的缓存图像视图:
import SwiftUI
import Combine
import UIKit
class ImageCache
enum Error: Swift.Error
case dataConversionFailed
case sessionError(Swift.Error)
static let shared = ImageCache()
private let cache = NSCache<NSURL, UIImage>()
private init()
static func image(for url: URL?) -> AnyPublisher<UIImage?, ImageCache.Error>
guard let url = url else
return Empty().eraseToAnyPublisher()
guard let image = shared.cache.object(forKey: url as NSURL) else
return URLSession
.shared
.dataTaskPublisher(for: url)
.tryMap (tuple) -> UIImage in
let (data, _) = tuple
guard let image = UIImage(data: data) else
throw Error.dataConversionFailed
shared.cache.setObject(image, forKey: url as NSURL)
return image
.mapError( error in Error.sessionError(error) )
.eraseToAnyPublisher()
return Just(image)
.mapError( _ in fatalError() )
.eraseToAnyPublisher()
class ImageModel: ObservableObject
@Published var image: UIImage? = nil
var cacheSubscription: AnyCancellable?
init(url: URL?)
cacheSubscription = ImageCache
.image(for: url)
.replaceError(with: nil)
.receive(on: RunLoop.main, options: .none)
.assign(to: \.image, on: self)
struct RemoteImage : View
@ObservedObject var imageModel: ImageModel
private let contentMode: ContentMode
init(url: URL?, contentMode: ContentMode = .fit)
imageModel = ImageModel(url: url)
self.contentMode = contentMode
var body: some View
imageModel
.image
.map Image(uiImage:$0).resizable().aspectRatio(contentMode: contentMode)
?? Image(systemName: "questionmark").resizable().aspectRatio(contentMode: contentMode)
【讨论】:
var
是什么意思?我的数据 var 已经是 @Published
,还是你说的是另一个 var?
你的视图是`var image: UIImage的函数? imageLoader.data.flatMap(UIImage.init) ` 这不是一个属性包装器,因此 SwiftUI 不知道您的计算属性何时更改并且视图永远不会重建
@Published var image: UIImage? ..
将返回`imageLoader.data.flatMap(UIImage.init)` 和@Published is only available on properties of classes
- 怎么会这样?
看我的例子:@published 属性在 ObservableObject 上,View 观察它。以上是关于SwiftUI 无法从下载地址获取图片的主要内容,如果未能解决你的问题,请参考以下文章
关于Java/Kotlin下载图片,图片打开不能显示问题探究
前端实现获取canvas下载地址以及下载basse64图片格式功能