简单轻量级的图像加载库,可以快速加载图像,因为它优先对图像进行排队,并按照请求的顺序加载图像。如果 ImageView 正在等待加载图像,则会优先于其他图像加载。它使用原生的 Image 对象加载图像,并提供了一种在内存中缓存它们的方法,您还可以设置自定义缓存大小。
负责从互联网下载图像的管理器。
负责在内存中缓存图像的管理器。 默认情况下
负责将图像排队等待下载,并优先处理正在被请求的图像的管理器。 优先级在运行时发生变化,因此在添加到下载队列之前会进行计算。 当图像 URL 附加到 UI 视图(也支持 SwiftUI)并且队列时间戳更接近当前时间时,优先级最高。
示例
for i in 0..<5 {
imageDownloader.prefetch(url: URL(string: "apple.com/image_\(i)")!)
}
ImageDownloader
立即开始下载前 2 个图像。let imageView = UIImageView()
imageView.setImage(withURL: URL(string: "apple.com/image\_\\(99)")!) // new URL
imageView.setImage(withURL: URL(string: "apple.com/image\_\\(3)")!) // <-- the same URL in queue
ImageDownloader
下载了 1 个图像,队列中空出了 1 个位置。
状态是
优先级算法将执行
下一个任务将选择 "image_3" with View (带有视图),因为它附加到 View,这意味着用户正在他的屏幕上等待这个图像。
应用程序必须实现的协议,代表网络层。
应用程序中的任何位置的示例
planeImageView.setImage(withURL: url, placeholder: .image(.planePlaceholder))
planeImageView.setImage(withURL: url, placeholder: .clear)
planeImageView.setImage(withURL: url)
UIImageView
扩展,便于使用
// extend UIImageView for loading images
public extension UIImageView {
func setImage(withURL url: URL,
animated animation: ImageAnimation? = nil,
placeholder: ImagePlaceholder = .none,
completion: ImageClosure? = nil) {
let info = ImageInfo(url: url)
ImageDownloader.shared.download(of: info,
for: self,
animated: animation,
placeholder: placeholder,
completion: completion ?? { _ in })
}
func cancelImageRequest() {
ImageDownloader.shared.cancel(for: self)
}
}
// MARK: - ImageDownloader + ImageDownloading
extension ImageDownloader: ImageDownloading {
public var imageCache: ImageCaching? {
return Self.shared.imageCache
}
public func prefetch(of info: ImageInfo,
completion: @escaping ImageClosure) {
Self.shared.prefetch(of: info, completion: completion)
}
public func prefetching(of info: SmartImages.ImageInfo, completion: @escaping SmartImages.ImageClosure) -> AnyCancellable {
return Self.shared.prefetching(of: info, completion: completion)
}
public func download(of info: ImageInfo,
completion: @escaping ImageClosure) -> AnyCancellable {
Self.shared.download(of: info,
completion: completion)
}
public func download(of info: ImageInfo,
for imageView: ImageView,
animated animation: ImageAnimation?,
placeholder: ImagePlaceholder = .none,
completion: @escaping ImageClosure) {
Self.shared.download(of: info,
for: imageView,
animated: animation,
placeholder: placeholder,
completion: completion)
}
public func cancel(for imageView: ImageView) {
Self.shared.cancel(for: imageView)
}
}
import Combine
import Foundation
import SmartImages
import SmartNetwork
import UIKit
public typealias ImageAnimation = SmartImages.ImageAnimation
public typealias ImageClosure = SmartImages.ImageClosure
public typealias ImageInfo = SmartImages.ImageInfo
public typealias ImagePlaceholder = SmartImages.ImagePlaceholder
public struct ImageDownloader {
private static let manager: RequestManagering = RequestManager.create() // <---- this is the place of your custom plugins, StopTheLine etc.
public static let shared: ImageDownloading = {
return SmartImages.ImageDownloader(network: ImageDownloaderNetworkAdaptor(manager: manager),
cache: .init(folderName: "DownloadedImages"),
concurrentLimit: 8)
}()
private init() {}
}
extension RequestingTask: @retroactive ImageDownloaderTask {}
private struct ImageDownloaderNetworkAdaptor: ImageDownloaderNetwork {
let manager: RequestManagering
func request(with url: URL,
cachePolicy: URLRequest.CachePolicy?,
timeoutInterval: TimeInterval?,
completion: @escaping ResultCompletion,
finishedOrCancelled finished: FinishedCompletion?) -> ImageDownloaderTask {
return manager.data.request(address: .init(url),
with: .init(requestPolicy: cachePolicy ?? .useProtocolCachePolicy,
timeoutInterval: timeoutInterval ?? RequestSettings.timeoutInterval),
inQueue: .absent,
completion: completion)
}
}
import Foundation
import SmartImages
import UIKit
public enum ImageDownloader {
private static let imageDownloader: ImageDownloading = {
return SmartImages.ImageDownloader.create(network: ImageDownloaderNetworkAdaptor(),
cache: .init(folderName: "DownloadedImages"),
concurrentImagesLimit: 8)
}()
public init() {}
}
private struct ImageDownloaderTaskAdaptor: ImageDownloaderTask {
let task: URLSessionTask
func start() {
task.resume()
}
func cancel() {
task.cancel()
}
}
private struct ImageDownloaderNetworkAdaptor: ImageDownloaderNetwork {
private let session: URLSession = .shared
func request(with url: URL,
cachePolicy: URLRequest.CachePolicy,
timeoutInterval: TimeInterval,
completion: @escaping (Result<Data, Error>) -> Void) -> ImageDownloaderTask {
let dataTask = session.dataTask(with: url) { data, _, error in
if let error {
completion(.failure(error))
} else if let data {
completion(.success(data))
} else {
completion(.failure(NSError(domain: "ImageDownloader", code: 0, userInfo: ["url": url])))
}
}
return ImageDownloaderTaskAdaptor(task: dataTask)
}
}