2 // KingfisherOptionsInfo.swift
5 // Created by Wei Wang on 15/4/23.
7 // Copyright (c) 2018 Wei Wang <onevcat@gmail.com>
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher.
37 public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
38 let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]()
41 Items could be added into KingfisherOptionsInfo.
43 public enum KingfisherOptionsInfoItem {
44 /// The associated value of this member should be an ImageCache object. Kingfisher will use the specified
45 /// cache object when handling related operations, including trying to retrieve the cached images and store
46 /// the downloaded image to it.
47 case targetCache(ImageCache)
49 /// Cache for storing and retrieving original image.
50 /// Preferred prior to targetCache for storing and retrieving original images if specified.
51 /// Only used if a non-default image processor is involved.
52 case originalCache(ImageCache)
54 /// The associated value of this member should be an ImageDownloader object. Kingfisher will use this
55 /// downloader to download the images.
56 case downloader(ImageDownloader)
58 /// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of
59 /// this enum to animate the image in if it is downloaded from web. The transition will not happen when the
60 /// image is retrieved from either memory or disk cache by default. If you need to do the transition even when
61 /// the image being retrieved from cache, set `ForceTransition` as well.
62 case transition(ImageTransition)
64 /// Associated `Float` value will be set as the priority of image download task. The value for it should be
65 /// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used.
66 case downloadPriority(Float)
68 /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource.
71 /// If set, `Kingfisher` will try to retrieve the image from memory cache first. If the image is not in memory
72 /// cache, then it will ignore the disk cache but download the image again from network. This is useful when
73 /// you want to display a changeable image behind the same url, while avoiding download it again and again.
74 case fromMemoryCacheOrRefresh
76 /// If set, setting the image to an image view will happen with transition even when retrieved from cache.
77 /// See `Transition` option for more.
80 /// If set, `Kingfisher` will only cache the value in memory but not in disk.
83 /// If set, `Kingfisher` will only try to retrieve the image from cache not from network.
86 /// Decode the image in background thread before using.
89 /// The associated value of this member will be used as the target queue of dispatch callbacks when
90 /// retrieving images from cache. If not set, `Kingfisher` will use main quese for callbacks.
91 case callbackDispatchQueue(DispatchQueue?)
93 /// The associated value of this member will be used as the scale factor when converting retrieved data to an image.
94 /// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing
95 /// with 2x or 3x retina images.
96 case scaleFactor(CGFloat)
98 /// Whether all the animated image data should be preloaded. Default it false, which means following frames will be
99 /// loaded on need. If true, all the animated image data will be loaded and decoded into memory. This option is mainly
100 /// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload
101 /// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use
102 /// corresponding image view type instead of setting this option.
103 case preloadAllAnimationData
105 /// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent.
106 /// This is the last chance you can modify the request. You can modify the request for some customizing purpose,
107 /// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request
108 /// will be sent without any modification by default.
109 case requestModifier(ImageDownloadRequestModifier)
111 /// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image
112 /// and/or apply some filter on it. If a cache is connected to the downloader (it happens when you are using
113 /// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the
114 /// image view. `DefaultImageProcessor.default` will be used by default.
115 case processor(ImageProcessor)
117 /// Supply an `CacheSerializer` to convert some data to an image object for
118 /// retrieving from disk cache or vice versa for storing to disk cache.
119 /// `DefaultCacheSerializer.default` will be used by default.
120 case cacheSerializer(CacheSerializer)
122 /// Modifier for modifying an image right before it is used.
123 /// If the image was fetched directly from the downloader, the modifier will
124 /// run directly after the processor.
125 /// If the image is being fetched from a cache, the modifier will run after
126 /// the cacheSerializer.
127 /// Use `ImageModifier` when you need to set properties on a concrete type
128 /// of `Image`, such as a `UIImage`, that do not persist when caching the image.
129 case imageModifier(ImageModifier)
131 /// Keep the existing image while setting another image to an image view.
132 /// By setting this option, the placeholder image parameter of imageview extension method
133 /// will be ignored and the current image will be kept while loading or downloading the new image.
134 case keepCurrentImageWhileLoading
136 /// If set, Kingfisher will only load the first frame from a animated image data file as a single image.
137 /// Loading a lot of animated images may take too much memory. It will be useful when you want to display a
138 /// static preview of the first frame from a animated image.
139 /// This option will be ignored if the target image is not animated image data.
140 case onlyLoadFirstFrame
142 /// If set and an `ImageProcessor` is used, Kingfisher will try to cache both
143 /// the final result and original image. Kingfisher will have a chance to use
144 /// the original image when another processor is applied to the same resouce,
145 /// instead of downloading it again.
146 case cacheOriginalImage
149 precedencegroup ItemComparisonPrecedence {
151 higherThan: LogicalConjunctionPrecedence
154 infix operator <== : ItemComparisonPrecedence
156 // This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
157 func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
159 case (.targetCache(_), .targetCache(_)): return true
160 case (.originalCache(_), .originalCache(_)): return true
161 case (.downloader(_), .downloader(_)): return true
162 case (.transition(_), .transition(_)): return true
163 case (.downloadPriority(_), .downloadPriority(_)): return true
164 case (.forceRefresh, .forceRefresh): return true
165 case (.fromMemoryCacheOrRefresh, .fromMemoryCacheOrRefresh): return true
166 case (.forceTransition, .forceTransition): return true
167 case (.cacheMemoryOnly, .cacheMemoryOnly): return true
168 case (.onlyFromCache, .onlyFromCache): return true
169 case (.backgroundDecode, .backgroundDecode): return true
170 case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
171 case (.scaleFactor(_), .scaleFactor(_)): return true
172 case (.preloadAllAnimationData, .preloadAllAnimationData): return true
173 case (.requestModifier(_), .requestModifier(_)): return true
174 case (.processor(_), .processor(_)): return true
175 case (.cacheSerializer(_), .cacheSerializer(_)): return true
176 case (.imageModifier(_), .imageModifier(_)): return true
177 case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
178 case (.onlyLoadFirstFrame, .onlyLoadFirstFrame): return true
179 case (.cacheOriginalImage, .cacheOriginalImage): return true
180 default: return false
185 extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
186 func lastMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
187 return reversed().first { $0 <== target }
190 func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
191 return filter { !($0 <== target) }
195 public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
196 /// The target `ImageCache` which is used.
197 public var targetCache: ImageCache {
198 if let item = lastMatchIgnoringAssociatedValue(.targetCache(.default)),
199 case .targetCache(let cache) = item
203 return ImageCache.default
206 /// The original `ImageCache` which is used.
207 public var originalCache: ImageCache {
208 if let item = lastMatchIgnoringAssociatedValue(.originalCache(.default)),
209 case .originalCache(let cache) = item
216 /// The `ImageDownloader` which is specified.
217 public var downloader: ImageDownloader {
218 if let item = lastMatchIgnoringAssociatedValue(.downloader(.default)),
219 case .downloader(let downloader) = item
223 return ImageDownloader.default
226 /// Member for animation transition when using UIImageView.
227 public var transition: ImageTransition {
228 if let item = lastMatchIgnoringAssociatedValue(.transition(.none)),
229 case .transition(let transition) = item
233 return ImageTransition.none
236 /// A `Float` value set as the priority of image download task. The value for it should be
238 public var downloadPriority: Float {
239 if let item = lastMatchIgnoringAssociatedValue(.downloadPriority(0)),
240 case .downloadPriority(let priority) = item
244 return URLSessionTask.defaultPriority
247 /// Whether an image will be always downloaded again or not.
248 public var forceRefresh: Bool {
249 return contains{ $0 <== .forceRefresh }
252 /// Whether an image should be got only from memory cache or download.
253 public var fromMemoryCacheOrRefresh: Bool {
254 return contains{ $0 <== .fromMemoryCacheOrRefresh }
257 /// Whether the transition should always happen or not.
258 public var forceTransition: Bool {
259 return contains{ $0 <== .forceTransition }
262 /// Whether cache the image only in memory or not.
263 public var cacheMemoryOnly: Bool {
264 return contains{ $0 <== .cacheMemoryOnly }
267 /// Whether only load the images from cache or not.
268 public var onlyFromCache: Bool {
269 return contains{ $0 <== .onlyFromCache }
272 /// Whether the image should be decoded in background or not.
273 public var backgroundDecode: Bool {
274 return contains{ $0 <== .backgroundDecode }
277 /// Whether the image data should be all loaded at once if it is an animated image.
278 public var preloadAllAnimationData: Bool {
279 return contains { $0 <== .preloadAllAnimationData }
282 /// The queue of callbacks should happen from Kingfisher.
283 public var callbackDispatchQueue: DispatchQueue {
284 if let item = lastMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
285 case .callbackDispatchQueue(let queue) = item
287 return queue ?? DispatchQueue.main
289 return DispatchQueue.main
292 /// The scale factor which should be used for the image.
293 public var scaleFactor: CGFloat {
294 if let item = lastMatchIgnoringAssociatedValue(.scaleFactor(0)),
295 case .scaleFactor(let scale) = item
302 /// The `ImageDownloadRequestModifier` will be used before sending a download request.
303 public var modifier: ImageDownloadRequestModifier {
304 if let item = lastMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
305 case .requestModifier(let modifier) = item
309 return NoModifier.default
312 /// `ImageProcessor` for processing when the downloading finishes.
313 public var processor: ImageProcessor {
314 if let item = lastMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
315 case .processor(let processor) = item
319 return DefaultImageProcessor.default
322 /// `ImageModifier` for modifying right before the image is displayed.
323 public var imageModifier: ImageModifier {
324 if let item = lastMatchIgnoringAssociatedValue(.imageModifier(DefaultImageModifier.default)),
325 case .imageModifier(let imageModifier) = item
329 return DefaultImageModifier.default
332 /// `CacheSerializer` to convert image to data for storing in cache.
333 public var cacheSerializer: CacheSerializer {
334 if let item = lastMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
335 case .cacheSerializer(let cacheSerializer) = item
337 return cacheSerializer
339 return DefaultCacheSerializer.default
342 /// Keep the existing image while setting another image to an image view.
343 /// Or the placeholder will be used while downloading.
344 public var keepCurrentImageWhileLoading: Bool {
345 return contains { $0 <== .keepCurrentImageWhileLoading }
348 public var onlyLoadFirstFrame: Bool {
349 return contains { $0 <== .onlyLoadFirstFrame }
352 public var cacheOriginalImage: Bool {
353 return contains { $0 <== .cacheOriginalImage }