Swift 迅捷可以';无法从下载url获取图像
我有以下代码从下载url加载图像并将其显示为UIImage 我希望它能工作,但不知何故,只显示占位符图像Swift 迅捷可以';无法从下载url获取图像,swift,swiftui,Swift,Swiftui,我有以下代码从下载url加载图像并将其显示为UIImage 我希望它能工作,但不知何故,只显示占位符图像'ccc',而不是下载url中的实际图像。怎么会这样 我的URL是从数据库中提取的,有点像这样: 您的图像是一个普通的旧var,在构建视图时恰好为零。SwiftUI只会根据@ObservedObject、@State或@Binding中的更改而重建自身,因此,将图像移动到图像加载器上的@Published属性,它就会工作。以下是我的缓存图像视图: import SwiftUI import
'ccc'
,而不是下载url中的实际图像。怎么会这样
我的URL是从数据库中提取的,有点像这样:
您的图像是一个普通的旧
var
,在构建视图时恰好为零。SwiftUI只会根据@ObservedObject
、@State
或@Binding
中的更改而重建自身,因此,将图像移动到图像加载器上的@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)
}
}
导入快捷界面
进口联合收割机
导入UIKit
类ImageCache{
枚举错误:Swift.Error{
案例数据转换失败
案件审理人错误(Swift.错误)
}
静态let shared=ImageCache()
private let cache=NSCache()
私有init(){}
静态func图像(用于url:url?->AnyPublisher{
guard let url=url else{
返回空()
}
guard let image=shared.cache.object(forKey:url作为NSURL)else{
返回URL会话
.共享
.dataTaskPublisher(用于:url)
.tryMap{(元组)->UIImage in
let(data,u)=元组
guard let image=UIImage(数据:数据)else{
抛出错误。DataConversion失败
}
shared.cache.setObject(图像,forKey:url为NSURL)
返回图像
}
.mapError({error中的error.sessionError(error)})
.删除任何发布者()
}
返回刚才(图片)
.mapError({inFatalError()})
.删除任何发布者()
}
}
类ImageModel:ObservableObject{
@已发布的var映像:UIImage?=nil
var cacheSubscription:是否可以取消?
初始化(url:url?){
cacheSubscription=ImageCache
.image(用于:url)
.replaceError(带:nil)
.receive(在:RunLoop.main上,选项:。无)
.assign(到:\.image,在:self上)
}
}
结构远程映像:视图{
@观测对象var图像模型:图像模型
私有let contentMode:contentMode
初始化(url:url?,contentMode:contentMode=.fit){
imageModel=imageModel(url:url)
self.contentMode=contentMode
}
var body:一些观点{
图像模型
.形象
.map{Image(uiImage:$0).resizeable().aspectRatio(contentMode:contentMode)}
??图像(系统名称:“问号”).resizeable().aspectRatio(内容模式:内容模式)
}
}
你是什么意思?我的数据变量已经发布了
,或者您讨论过另一个变量吗?您的视图是`var image:UIImage'的函数?{imageLoader.data.flatMap(UIImage.init)}`这不是一个属性包装器,所以SwiftUI不知道您的计算属性何时更改,视图永远无法重建@Published var image:UIImage?{..
将返回`imageLoader.data.flatMap(UIImage.init)`并且@Published仅在类的属性上可用
-如何?请看我的示例:@Published属性在一个observeObject上,视图观察它。
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()
}
}
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)
}
}