KingfisherOptionsInfo.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. //
  2. // KingfisherOptionsInfo.swift
  3. // Kingfisher
  4. //
  5. // Created by Wei Wang on 15/4/23.
  6. //
  7. // Copyright (c) 2016 Wei Wang <onevcat@gmail.com>
  8. //
  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:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  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
  25. // THE SOFTWARE.
  26. #if os(macOS)
  27. import AppKit
  28. #else
  29. import UIKit
  30. #endif
  31. /**
  32. * KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher.
  33. */
  34. public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
  35. let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]()
  36. /**
  37. Items could be added into KingfisherOptionsInfo.
  38. */
  39. public enum KingfisherOptionsInfoItem {
  40. /// The associated value of this member should be an ImageCache object. Kingfisher will use the specified
  41. /// cache object when handling related operations, including trying to retrieve the cached images and store
  42. /// the downloaded image to it.
  43. case targetCache(ImageCache)
  44. /// The associated value of this member should be an ImageDownloader object. Kingfisher will use this
  45. /// downloader to download the images.
  46. case downloader(ImageDownloader)
  47. /// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of
  48. /// this enum to animate the image in if it is downloaded from web. The transition will not happen when the
  49. /// image is retrieved from either memory or disk cache by default. If you need to do the transition even when
  50. /// the image being retrieved from cache, set `ForceTransition` as well.
  51. case transition(ImageTransition)
  52. /// Associated `Float` value will be set as the priority of image download task. The value for it should be
  53. /// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used.
  54. case downloadPriority(Float)
  55. /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource.
  56. case forceRefresh
  57. /// If set, setting the image to an image view will happen with transition even when retrieved from cache.
  58. /// See `Transition` option for more.
  59. case forceTransition
  60. /// If set, `Kingfisher` will only cache the value in memory but not in disk.
  61. case cacheMemoryOnly
  62. /// If set, `Kingfisher` will only try to retrieve the image from cache not from network.
  63. case onlyFromCache
  64. /// Decode the image in background thread before using.
  65. case backgroundDecode
  66. /// The associated value of this member will be used as the target queue of dispatch callbacks when
  67. /// retrieving images from cache. If not set, `Kingfisher` will use main quese for callbacks.
  68. case callbackDispatchQueue(DispatchQueue?)
  69. /// The associated value of this member will be used as the scale factor when converting retrieved data to an image.
  70. /// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing
  71. /// with 2x or 3x retina images.
  72. case scaleFactor(CGFloat)
  73. /// Whether all the GIF data should be preloaded. Default it false, which means following frames will be
  74. /// loaded on need. If true, all the GIF data will be loaded and decoded into memory. This option is mainly
  75. /// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload
  76. /// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use
  77. /// corresponding image view type instead of setting this option.
  78. case preloadAllGIFData
  79. /// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent.
  80. /// This is the last chance you can modify the request. You can modify the request for some customizing purpose,
  81. /// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request
  82. /// will be sent without any modification by default.
  83. case requestModifier(ImageDownloadRequestModifier)
  84. /// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image
  85. /// and/or apply some filter on it. If a cache is connected to the downloader (it happenes when you are using
  86. /// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the
  87. /// image view. `DefaultImageProcessor.default` will be used by default.
  88. case processor(ImageProcessor)
  89. /// Supply an `CacheSerializer` to convert some data to an image object for
  90. /// retrieving from disk cache or vice versa for storing to disk cache.
  91. /// `DefaultCacheSerializer.default` will be used by default.
  92. case cacheSerializer(CacheSerializer)
  93. /// Keep the existing image while setting another image to an image view.
  94. /// By setting this option, the placeholder image parameter of imageview extension method
  95. /// will be ignored and the current image will be kept while loading or downloading the new image.
  96. case keepCurrentImageWhileLoading
  97. }
  98. precedencegroup ItemComparisonPrecedence {
  99. associativity: none
  100. higherThan: LogicalConjunctionPrecedence
  101. }
  102. infix operator <== : ItemComparisonPrecedence
  103. // This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
  104. func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
  105. switch (lhs, rhs) {
  106. case (.targetCache(_), .targetCache(_)): return true
  107. case (.downloader(_), .downloader(_)): return true
  108. case (.transition(_), .transition(_)): return true
  109. case (.downloadPriority(_), .downloadPriority(_)): return true
  110. case (.forceRefresh, .forceRefresh): return true
  111. case (.forceTransition, .forceTransition): return true
  112. case (.cacheMemoryOnly, .cacheMemoryOnly): return true
  113. case (.onlyFromCache, .onlyFromCache): return true
  114. case (.backgroundDecode, .backgroundDecode): return true
  115. case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
  116. case (.scaleFactor(_), .scaleFactor(_)): return true
  117. case (.preloadAllGIFData, .preloadAllGIFData): return true
  118. case (.requestModifier(_), .requestModifier(_)): return true
  119. case (.processor(_), .processor(_)): return true
  120. case (.cacheSerializer(_), .cacheSerializer(_)): return true
  121. case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
  122. default: return false
  123. }
  124. }
  125. extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
  126. func firstMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
  127. return index { $0 <== target }.flatMap { self[$0] }
  128. }
  129. func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
  130. return self.filter { !($0 <== target) }
  131. }
  132. }
  133. public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
  134. /// The target `ImageCache` which is used.
  135. public var targetCache: ImageCache {
  136. if let item = firstMatchIgnoringAssociatedValue(.targetCache(.default)),
  137. case .targetCache(let cache) = item
  138. {
  139. return cache
  140. }
  141. return ImageCache.default
  142. }
  143. /// The `ImageDownloader` which is specified.
  144. public var downloader: ImageDownloader {
  145. if let item = firstMatchIgnoringAssociatedValue(.downloader(.default)),
  146. case .downloader(let downloader) = item
  147. {
  148. return downloader
  149. }
  150. return ImageDownloader.default
  151. }
  152. /// Member for animation transition when using UIImageView.
  153. public var transition: ImageTransition {
  154. if let item = firstMatchIgnoringAssociatedValue(.transition(.none)),
  155. case .transition(let transition) = item
  156. {
  157. return transition
  158. }
  159. return ImageTransition.none
  160. }
  161. /// A `Float` value set as the priority of image download task. The value for it should be
  162. /// between 0.0~1.0.
  163. public var downloadPriority: Float {
  164. if let item = firstMatchIgnoringAssociatedValue(.downloadPriority(0)),
  165. case .downloadPriority(let priority) = item
  166. {
  167. return priority
  168. }
  169. return URLSessionTask.defaultPriority
  170. }
  171. /// Whether an image will be always downloaded again or not.
  172. public var forceRefresh: Bool {
  173. return contains{ $0 <== .forceRefresh }
  174. }
  175. /// Whether the transition should always happen or not.
  176. public var forceTransition: Bool {
  177. return contains{ $0 <== .forceTransition }
  178. }
  179. /// Whether cache the image only in memory or not.
  180. public var cacheMemoryOnly: Bool {
  181. return contains{ $0 <== .cacheMemoryOnly }
  182. }
  183. /// Whether only load the images from cache or not.
  184. public var onlyFromCache: Bool {
  185. return contains{ $0 <== .onlyFromCache }
  186. }
  187. /// Whether the image should be decoded in background or not.
  188. public var backgroundDecode: Bool {
  189. return contains{ $0 <== .backgroundDecode }
  190. }
  191. /// Whether the image data should be all loaded at once if it is a GIF.
  192. public var preloadAllGIFData: Bool {
  193. return contains { $0 <== .preloadAllGIFData }
  194. }
  195. /// The queue of callbacks should happen from Kingfisher.
  196. public var callbackDispatchQueue: DispatchQueue {
  197. if let item = firstMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
  198. case .callbackDispatchQueue(let queue) = item
  199. {
  200. return queue ?? DispatchQueue.main
  201. }
  202. return DispatchQueue.main
  203. }
  204. /// The scale factor which should be used for the image.
  205. public var scaleFactor: CGFloat {
  206. if let item = firstMatchIgnoringAssociatedValue(.scaleFactor(0)),
  207. case .scaleFactor(let scale) = item
  208. {
  209. return scale
  210. }
  211. return 1.0
  212. }
  213. /// The `ImageDownloadRequestModifier` will be used before sending a download request.
  214. public var modifier: ImageDownloadRequestModifier {
  215. if let item = firstMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
  216. case .requestModifier(let modifier) = item
  217. {
  218. return modifier
  219. }
  220. return NoModifier.default
  221. }
  222. /// `ImageProcessor` for processing when the downloading finishes.
  223. public var processor: ImageProcessor {
  224. if let item = firstMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
  225. case .processor(let processor) = item
  226. {
  227. return processor
  228. }
  229. return DefaultImageProcessor.default
  230. }
  231. /// `CacheSerializer` to convert image to data for storing in cache.
  232. public var cacheSerializer: CacheSerializer {
  233. if let item = firstMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
  234. case .cacheSerializer(let cacheSerializer) = item
  235. {
  236. return cacheSerializer
  237. }
  238. return DefaultCacheSerializer.default
  239. }
  240. /// Keep the existing image while setting another image to an image view.
  241. /// Or the placeholder will be used while downloading.
  242. public var keepCurrentImageWhileLoading: Bool {
  243. return contains { $0 <== .keepCurrentImageWhileLoading }
  244. }
  245. }