В SwiftUI есть несколько .init
методов для создания образа, но ни один из них не допускает блок или любой другой способ загрузки UIImage из сети / кэша ...
Я использую Kingfisher для загрузки изображений из сети и кэширования в строке списка, но способ отрисовки изображения в представлении состоит в том, чтобы повторно отрендерить его, чего я бы предпочел не делать , Кроме того, я создаю поддельное изображение (только цветное) в качестве заполнителя, пока изображение извлекается.
Другим способом было бы обернуть все внутри пользовательского представления и перерисовать только оболочку. Но я еще не пробовал.
Этот образец работает прямо сейчас.
Любая идея улучшить текущую будет отличной
Некоторый вид с использованием загрузчика
struct SampleView : View {
@ObjectBinding let imageLoader: ImageLoader
init(imageLoader: ImageLoader) {
self.imageLoader = imageLoader
}
var body: some View {
Image(uiImage: imageLoader.image(for: "https://url-for-image"))
.frame(width: 128, height: 128)
.aspectRatio(contentMode: ContentMode.fit)
}
}
import UIKit.UIImage
import SwiftUI
import Combine
import class Kingfisher.ImageDownloader
import struct Kingfisher.DownloadTask
import class Kingfisher.ImageCache
import class Kingfisher.KingfisherManager
class ImageLoader: BindableObject {
var didChange = PassthroughSubject<ImageLoader, Never>()
private let downloader: ImageDownloader
private let cache: ImageCache
private var image: UIImage? {
didSet {
dispatchqueue.async { [weak self] in
guard let self = self else { return }
self.didChange.send(self)
}
}
}
private var task: DownloadTask?
private let dispatchqueue: DispatchQueue
init(downloader: ImageDownloader = KingfisherManager.shared.downloader,
cache: ImageCache = KingfisherManager.shared.cache,
dispatchqueue: DispatchQueue = DispatchQueue.main) {
self.downloader = downloader
self.cache = cache
self.dispatchqueue = dispatchqueue
}
deinit {
task?.cancel()
}
func image(for url: URL?) -> UIImage {
guard let targetUrl = url else {
return UIImage.from(color: .gray)
}
guard let image = image else {
load(url: targetUrl)
return UIImage.from(color: .gray)
}
return image
}
private func load(url: URL) {
let key = url.absoluteString
if cache.isCached(forKey: key) {
cache.retrieveImage(forKey: key) { [weak self] (result) in
guard let self = self else { return }
switch result {
case .success(let value):
self.image = value.image
case .failure(let error):
print(error.localizedDescription)
}
}
} else {
downloader.downloadImage(with: url, options: nil, progressBlock: nil) { [weak self] (result) in
guard let self = self else { return }
switch result {
case .success(let value):
self.cache.storeToDisk(value.originalData, forKey: url.absoluteString)
self.image = value.image
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
}