123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- //
- // KingfisherOptionsInfo.swift
- // Kingfisher
- //
- // Created by Wei Wang on 15/4/23.
- //
- // Copyright (c) 2018 Wei Wang <onevcat@gmail.com>
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- #if os(macOS)
- import AppKit
- #else
- import UIKit
- #endif
-
- /**
- * KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher.
- */
- public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
- let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]()
- /**
- Items could be added into KingfisherOptionsInfo.
- */
- public enum KingfisherOptionsInfoItem {
- /// The associated value of this member should be an ImageCache object. Kingfisher will use the specified
- /// cache object when handling related operations, including trying to retrieve the cached images and store
- /// the downloaded image to it.
- case targetCache(ImageCache)
-
- /// Cache for storing and retrieving original image.
- /// Preferred prior to targetCache for storing and retrieving original images if specified.
- /// Only used if a non-default image processor is involved.
- case originalCache(ImageCache)
-
- /// The associated value of this member should be an ImageDownloader object. Kingfisher will use this
- /// downloader to download the images.
- case downloader(ImageDownloader)
-
- /// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of
- /// this enum to animate the image in if it is downloaded from web. The transition will not happen when the
- /// image is retrieved from either memory or disk cache by default. If you need to do the transition even when
- /// the image being retrieved from cache, set `ForceTransition` as well.
- case transition(ImageTransition)
-
- /// Associated `Float` value will be set as the priority of image download task. The value for it should be
- /// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used.
- case downloadPriority(Float)
-
- /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource.
- case forceRefresh
- /// If set, `Kingfisher` will try to retrieve the image from memory cache first. If the image is not in memory
- /// cache, then it will ignore the disk cache but download the image again from network. This is useful when
- /// you want to display a changeable image behind the same url, while avoiding download it again and again.
- case fromMemoryCacheOrRefresh
-
- /// If set, setting the image to an image view will happen with transition even when retrieved from cache.
- /// See `Transition` option for more.
- case forceTransition
-
- /// If set, `Kingfisher` will only cache the value in memory but not in disk.
- case cacheMemoryOnly
-
- /// If set, `Kingfisher` will wait for caching operation to be completed before calling the completion block.
- case waitForCache
-
- /// If set, `Kingfisher` will only try to retrieve the image from cache not from network.
- case onlyFromCache
-
- /// Decode the image in background thread before using.
- case backgroundDecode
-
- /// The associated value of this member will be used as the target queue of dispatch callbacks when
- /// retrieving images from cache. If not set, `Kingfisher` will use main queue for callbacks.
- case callbackDispatchQueue(DispatchQueue?)
-
- /// The associated value of this member will be used as the scale factor when converting retrieved data to an image.
- /// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing
- /// with 2x or 3x retina images.
- case scaleFactor(CGFloat)
- /// Whether all the animated image data should be preloaded. Default it false, which means following frames will be
- /// loaded on need. If true, all the animated image data will be loaded and decoded into memory. This option is mainly
- /// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload
- /// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use
- /// corresponding image view type instead of setting this option.
- case preloadAllAnimationData
-
- /// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent.
- /// This is the last chance you can modify the request. You can modify the request for some customizing purpose,
- /// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request
- /// will be sent without any modification by default.
- case requestModifier(ImageDownloadRequestModifier)
-
- /// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image
- /// and/or apply some filter on it. If a cache is connected to the downloader (it happens when you are using
- /// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the
- /// image view. `DefaultImageProcessor.default` will be used by default.
- case processor(ImageProcessor)
-
- /// Supply an `CacheSerializer` to convert some data to an image object for
- /// retrieving from disk cache or vice versa for storing to disk cache.
- /// `DefaultCacheSerializer.default` will be used by default.
- case cacheSerializer(CacheSerializer)
- /// Modifier for modifying an image right before it is used.
- /// If the image was fetched directly from the downloader, the modifier will
- /// run directly after the processor.
- /// If the image is being fetched from a cache, the modifier will run after
- /// the cacheSerializer.
- /// Use `ImageModifier` when you need to set properties on a concrete type
- /// of `Image`, such as a `UIImage`, that do not persist when caching the image.
- case imageModifier(ImageModifier)
-
- /// Keep the existing image while setting another image to an image view.
- /// By setting this option, the placeholder image parameter of imageview extension method
- /// will be ignored and the current image will be kept while loading or downloading the new image.
- case keepCurrentImageWhileLoading
-
- /// If set, Kingfisher will only load the first frame from a animated image data file as a single image.
- /// Loading a lot of animated images may take too much memory. It will be useful when you want to display a
- /// static preview of the first frame from a animated image.
- /// This option will be ignored if the target image is not animated image data.
- case onlyLoadFirstFrame
-
- /// If set and an `ImageProcessor` is used, Kingfisher will try to cache both
- /// the final result and original image. Kingfisher will have a chance to use
- /// the original image when another processor is applied to the same resource,
- /// instead of downloading it again.
- case cacheOriginalImage
- }
- precedencegroup ItemComparisonPrecedence {
- associativity: none
- higherThan: LogicalConjunctionPrecedence
- }
- infix operator <== : ItemComparisonPrecedence
- // This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
- func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
- switch (lhs, rhs) {
- case (.targetCache(_), .targetCache(_)): return true
- case (.originalCache(_), .originalCache(_)): return true
- case (.downloader(_), .downloader(_)): return true
- case (.transition(_), .transition(_)): return true
- case (.downloadPriority(_), .downloadPriority(_)): return true
- case (.forceRefresh, .forceRefresh): return true
- case (.fromMemoryCacheOrRefresh, .fromMemoryCacheOrRefresh): return true
- case (.forceTransition, .forceTransition): return true
- case (.cacheMemoryOnly, .cacheMemoryOnly): return true
- case (.waitForCache, .waitForCache): return true
- case (.onlyFromCache, .onlyFromCache): return true
- case (.backgroundDecode, .backgroundDecode): return true
- case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
- case (.scaleFactor(_), .scaleFactor(_)): return true
- case (.preloadAllAnimationData, .preloadAllAnimationData): return true
- case (.requestModifier(_), .requestModifier(_)): return true
- case (.processor(_), .processor(_)): return true
- case (.cacheSerializer(_), .cacheSerializer(_)): return true
- case (.imageModifier(_), .imageModifier(_)): return true
- case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
- case (.onlyLoadFirstFrame, .onlyLoadFirstFrame): return true
- case (.cacheOriginalImage, .cacheOriginalImage): return true
- default: return false
- }
- }
- extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
- func lastMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
- return reversed().first { $0 <== target }
- }
-
- func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
- return filter { !($0 <== target) }
- }
- }
- public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
- /// The target `ImageCache` which is used.
- public var targetCache: ImageCache? {
- if let item = lastMatchIgnoringAssociatedValue(.targetCache(.default)),
- case .targetCache(let cache) = item
- {
- return cache
- }
- return nil
- }
-
- /// The original `ImageCache` which is used.
- public var originalCache: ImageCache? {
- if let item = lastMatchIgnoringAssociatedValue(.originalCache(.default)),
- case .originalCache(let cache) = item
- {
- return cache
- }
- return targetCache
- }
-
- /// The `ImageDownloader` which is specified.
- public var downloader: ImageDownloader? {
- if let item = lastMatchIgnoringAssociatedValue(.downloader(.default)),
- case .downloader(let downloader) = item
- {
- return downloader
- }
- return nil
- }
-
- /// Member for animation transition when using UIImageView.
- public var transition: ImageTransition {
- if let item = lastMatchIgnoringAssociatedValue(.transition(.none)),
- case .transition(let transition) = item
- {
- return transition
- }
- return ImageTransition.none
- }
-
- /// A `Float` value set as the priority of image download task. The value for it should be
- /// between 0.0~1.0.
- public var downloadPriority: Float {
- if let item = lastMatchIgnoringAssociatedValue(.downloadPriority(0)),
- case .downloadPriority(let priority) = item
- {
- return priority
- }
- return URLSessionTask.defaultPriority
- }
-
- /// Whether an image will be always downloaded again or not.
- public var forceRefresh: Bool {
- return contains{ $0 <== .forceRefresh }
- }
- /// Whether an image should be got only from memory cache or download.
- public var fromMemoryCacheOrRefresh: Bool {
- return contains{ $0 <== .fromMemoryCacheOrRefresh }
- }
-
- /// Whether the transition should always happen or not.
- public var forceTransition: Bool {
- return contains{ $0 <== .forceTransition }
- }
-
- /// Whether cache the image only in memory or not.
- public var cacheMemoryOnly: Bool {
- return contains{ $0 <== .cacheMemoryOnly }
- }
-
- /// Whether the caching operation will be waited or not.
- public var waitForCache: Bool {
- return contains{ $0 <== .waitForCache }
- }
-
- /// Whether only load the images from cache or not.
- public var onlyFromCache: Bool {
- return contains{ $0 <== .onlyFromCache }
- }
-
- /// Whether the image should be decoded in background or not.
- public var backgroundDecode: Bool {
- return contains{ $0 <== .backgroundDecode }
- }
- /// Whether the image data should be all loaded at once if it is an animated image.
- public var preloadAllAnimationData: Bool {
- return contains { $0 <== .preloadAllAnimationData }
- }
-
- /// The queue of callbacks should happen from Kingfisher.
- public var callbackDispatchQueue: DispatchQueue {
- if let item = lastMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
- case .callbackDispatchQueue(let queue) = item
- {
- return queue ?? DispatchQueue.main
- }
- return DispatchQueue.main
- }
-
- /// The scale factor which should be used for the image.
- public var scaleFactor: CGFloat {
- if let item = lastMatchIgnoringAssociatedValue(.scaleFactor(0)),
- case .scaleFactor(let scale) = item
- {
- return scale
- }
- return 1.0
- }
-
- /// The `ImageDownloadRequestModifier` will be used before sending a download request.
- public var modifier: ImageDownloadRequestModifier {
- if let item = lastMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
- case .requestModifier(let modifier) = item
- {
- return modifier
- }
- return NoModifier.default
- }
-
- /// `ImageProcessor` for processing when the downloading finishes.
- public var processor: ImageProcessor {
- if let item = lastMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
- case .processor(let processor) = item
- {
- return processor
- }
- return DefaultImageProcessor.default
- }
- /// `ImageModifier` for modifying right before the image is displayed.
- public var imageModifier: ImageModifier {
- if let item = lastMatchIgnoringAssociatedValue(.imageModifier(DefaultImageModifier.default)),
- case .imageModifier(let imageModifier) = item
- {
- return imageModifier
- }
- return DefaultImageModifier.default
- }
-
- /// `CacheSerializer` to convert image to data for storing in cache.
- public var cacheSerializer: CacheSerializer {
- if let item = lastMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
- case .cacheSerializer(let cacheSerializer) = item
- {
- return cacheSerializer
- }
- return DefaultCacheSerializer.default
- }
-
- /// Keep the existing image while setting another image to an image view.
- /// Or the placeholder will be used while downloading.
- public var keepCurrentImageWhileLoading: Bool {
- return contains { $0 <== .keepCurrentImageWhileLoading }
- }
-
- public var onlyLoadFirstFrame: Bool {
- return contains { $0 <== .onlyLoadFirstFrame }
- }
-
- public var cacheOriginalImage: Bool {
- return contains { $0 <== .cacheOriginalImage }
- }
- }
|