// The MIT License (MIT) // // Copyright (c) 2015-2022 Alexander Grebenyuk (github.com/kean). import Foundation import os // MARK: - ImagePipeline.Configuration extension ImagePipeline { /// The pipeline configuration. public struct Configuration { // MARK: - Dependencies /// Image cache used by the pipeline. public var imageCache: ImageCaching? { // This exists simply to ensure we don't init ImageCache.shared if the // user provides their own instance. get { isCustomImageCacheProvided ? customImageCache : ImageCache.shared } set { customImageCache = newValue isCustomImageCacheProvided = true } } private var customImageCache: ImageCaching? /// Data loader used by the pipeline. public var dataLoader: DataLoading /// Data cache used by the pipeline. public var dataCache: DataCaching? /// Default implementation uses shared `ImageDecoderRegistry` to create /// a decoder that matches the context. public var makeImageDecoder: (ImageDecodingContext) -> ImageDecoding? = ImageDecoderRegistry.shared.decoder(for:) /// Returns `ImageEncoders.Default()` by default. public var makeImageEncoder: (ImageEncodingContext) -> ImageEncoding = { _ in ImageEncoders.Default() } // MARK: - Operation Queues /// Data loading queue. Default maximum concurrent task count is 6. public var dataLoadingQueue = OperationQueue(maxConcurrentCount: 6) /// Data caching queue. Default maximum concurrent task count is 2. public var dataCachingQueue = OperationQueue(maxConcurrentCount: 2) /// Image decoding queue. Default maximum concurrent task count is 1. public var imageDecodingQueue = OperationQueue(maxConcurrentCount: 1) /// Image encoding queue. Default maximum concurrent task count is 1. public var imageEncodingQueue = OperationQueue(maxConcurrentCount: 1) /// Image processing queue. Default maximum concurrent task count is 2. public var imageProcessingQueue = OperationQueue(maxConcurrentCount: 2) #if !os(macOS) /// Image decompressing queue. Default maximum concurrent task count is 2. public var imageDecompressingQueue = OperationQueue(maxConcurrentCount: 2) #endif // MARK: - Options /// A queue on which all callbacks, like `progress` and `completion` /// callbacks are called. `.main` by default. public var callbackQueue = DispatchQueue.main #if !os(macOS) /// Decompresses the loaded images. `true` by default. /// /// Decompressing compressed image formats (such as JPEG) can significantly /// improve drawing performance as it allows a bitmap representation to be /// created in a background rather than on the main thread. public var isDecompressionEnabled = true #endif /// `.storeOriginalData` by default. public var dataCachePolicy = DataCachePolicy.storeOriginalData /// Determines what images are stored in the disk cache. public enum DataCachePolicy { /// For requests with processors, encode and store processed images. /// For requests with no processors, store original image data, unless /// the resource is local (file:// or data:// scheme is used). /// /// - warning: With this policy, the pipeline `loadData()` method /// will not store the images in the disk cache for requests with /// any processors applied – this method only loads data and doesn't /// decode images. case automatic /// For all requests, only store the original image data, unless /// the resource is local (file:// or data:// scheme is used). case storeOriginalData /// For all requests, encode and store decoded images after all /// processors are applied. /// /// - note: This is useful if you want to store images in a format /// different than provided by a server, e.g. decompressed. In other /// scenarios, consider using `.automatic` policy instead. /// /// - warning: With this policy, the pipeline `loadData()` method /// will not store the images in the disk cache – this method only /// loads data and doesn't decode images. case storeEncodedImages /// For requests with processors, encode and store processed images. /// For all requests, store original image data. case storeAll } // Deprecated in 10.0.0 @available(*, deprecated, message: "Please use `dataCachePolicy` instead.") public var dataCacheOptions: DataCacheOptions = DataCacheOptions() { didSet { let items = dataCacheOptions.storedItems if items == [.finalImage] { dataCachePolicy = .storeEncodedImages } else if items == [.originalImageData] { dataCachePolicy = .storeOriginalData } else if items == [.finalImage, .originalImageData] { dataCachePolicy = .storeAll } } } // Deprecated in 10.0.0 @available(*, deprecated, message: "Please use `dataCachePolicy` instead. The recommended policy is the new `.automatic` policy.") public struct DataCacheOptions { public var storedItems: Set = [.originalImageData] } // Deprecated in 10.0.0 var _processors: [ImageProcessing] = [] /// `true` by default. If `true` the pipeline avoids duplicated work when /// loading images. The work only gets cancelled when all the registered /// requests are. The pipeline also automatically manages the priority of the /// deduplicated work. /// /// Let's take these two requests for example: /// /// ```swift /// let url = URL(string: "http://example.com/image") /// pipeline.loadImage(with: ImageRequest(url: url, processors: [ /// ImageProcessors.Resize(size: CGSize(width: 44, height: 44)), /// ImageProcessors.GaussianBlur(radius: 8) /// ])) /// pipeline.loadImage(with: ImageRequest(url: url, processors: [ /// ImageProcessors.Resize(size: CGSize(width: 44, height: 44)) /// ])) /// ``` /// /// Nuke will load the image data only once, resize the image once and /// apply the blur also only once. There is no duplicated work done at /// any stage. public var isTaskCoalescingEnabled = true /// `true` by default. If `true` the pipeline will rate limit requests /// to prevent trashing of the underlying systems (e.g. `URLSession`). /// The rate limiter only comes into play when the requests are started /// and cancelled at a high rate (e.g. scrolling through a collection view). public var isRateLimiterEnabled = true /// `false` by default. If `true` the pipeline will try to produce a new /// image each time it receives a new portion of data from data loader. /// The decoder used by the image loading session determines whether /// to produce a partial image or not. The default image decoder /// (`ImageDecoder`) supports progressive JPEG decoding. public var isProgressiveDecodingEnabled = true /// `false` by default. If `true`, the pipeline will store all of the /// progressively generated previews in the memory cache. All of the /// previews have `isPreview` flag set to `true`. public var isStoringPreviewsInMemoryCache = true /// If the data task is terminated (either because of a failure or a /// cancellation) and the image was partially loaded, the next load will /// resume where it left off. Supports both validators (`ETag`, /// `Last-Modified`). Resumable downloads are enabled by default. public var isResumableDataEnabled = true // MARK: - Options (Shared) /// If `true` pipeline will detect GIFs and set `animatedImageData` /// (`UIImage` property). It will also disable processing of such images, /// and alter the way cache cost is calculated. However, this will not /// enable actual animated image rendering. To do that take a look at /// satellite projects (FLAnimatedImage and Gifu plugins for Nuke). /// `false` by default (to preserve resources). static var _isAnimatedImageDataEnabled = false /// `false` by default. If `true`, enables `os_signpost` logging for /// measuring performance. You can visually see all the performance /// metrics in `os_signpost` Instrument. For more information see /// https://developer.apple.com/documentation/os/logging and /// https://developer.apple.com/videos/play/wwdc2018/405/. public static var isSignpostLoggingEnabled = false { didSet { log = isSignpostLoggingEnabled ? OSLog(subsystem: "com.github.kean.Nuke.ImagePipeline", category: "Image Loading") : .disabled } } private var isCustomImageCacheProvided = false var debugIsSyncImageEncoding = false // MARK: - Initializer /// Instantiates a default pipeline configuration. /// /// - parameter dataLoader: `DataLoader()` by default. public init(dataLoader: DataLoading = DataLoader()) { self.dataLoader = dataLoader } /// A configuration with a `DataLoader` with an HTTP disk cache (`URLCache`) /// with a size limit of 150 MB. public static var withURLCache: Configuration { Configuration() } /// A configuration with an aggressive disk cache (`DataCache`) with a /// size limit of 150 MB. An HTTP cache (`URLCache`) is disabled. public static var withDataCache: Configuration { let dataLoader: DataLoader = { let config = URLSessionConfiguration.default config.urlCache = nil return DataLoader(configuration: config) }() var config = Configuration() config.dataLoader = dataLoader config.dataCache = try? DataCache(name: "com.github.kean.Nuke.DataCache") return config } } }