NSButton+Kingfisher.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //
  2. // NSButton+Kingfisher.swift
  3. // Kingfisher
  4. //
  5. // Created by Jie Zhang on 14/04/2016.
  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. import AppKit
  27. // MARK: - Set Images
  28. /**
  29. * Set image to use from web.
  30. */
  31. extension NSButton {
  32. /**
  33. Set an image with a URL, a placeholder image, options, progress handler and completion handler.
  34. - parameter URL: The URL of image.
  35. - parameter placeholderImage: A placeholder image when retrieving the image at URL.
  36. - parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
  37. - parameter progressBlock: Called when the image downloading progress gets updated.
  38. - parameter completionHandler: Called when the image retrieved and set.
  39. - returns: A task represents the retrieving process.
  40. - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
  41. The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
  42. */
  43. public func kf_setImageWithURL(URL: NSURL,
  44. placeholderImage: Image? = nil,
  45. optionsInfo: KingfisherOptionsInfo? = nil,
  46. progressBlock: DownloadProgressBlock? = nil,
  47. completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
  48. {
  49. return kf_setImageWithResource(Resource(downloadURL: URL),
  50. placeholderImage: placeholderImage,
  51. optionsInfo: optionsInfo,
  52. progressBlock: progressBlock,
  53. completionHandler: completionHandler)
  54. }
  55. /**
  56. Set an image with a URL, a placeholder image, options, progress handler and completion handler.
  57. - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
  58. - parameter placeholderImage: A placeholder image when retrieving the image at URL.
  59. - parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
  60. - parameter progressBlock: Called when the image downloading progress gets updated.
  61. - parameter completionHandler: Called when the image retrieved and set.
  62. - returns: A task represents the retrieving process.
  63. - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
  64. The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
  65. */
  66. public func kf_setImageWithResource(resource: Resource,
  67. placeholderImage: Image? = nil,
  68. optionsInfo: KingfisherOptionsInfo? = nil,
  69. progressBlock: DownloadProgressBlock? = nil,
  70. completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
  71. {
  72. image = placeholderImage
  73. kf_setWebURL(resource.downloadURL)
  74. let task = KingfisherManager.sharedManager.retrieveImageWithResource(resource, optionsInfo: optionsInfo,
  75. progressBlock: { receivedSize, totalSize in
  76. if let progressBlock = progressBlock {
  77. progressBlock(receivedSize: receivedSize, totalSize: totalSize)
  78. }
  79. },
  80. completionHandler: {[weak self] image, error, cacheType, imageURL in
  81. dispatch_async_safely_to_main_queue {
  82. guard let sSelf = self where imageURL == sSelf.kf_webURL else {
  83. completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
  84. return
  85. }
  86. sSelf.kf_setImageTask(nil)
  87. guard let image = image else {
  88. completionHandler?(image: nil, error: error, cacheType: cacheType, imageURL: imageURL)
  89. return
  90. }
  91. sSelf.image = image
  92. completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
  93. }
  94. })
  95. kf_setImageTask(task)
  96. return task
  97. }
  98. }
  99. // MARK: - Associated Object
  100. private var lastURLKey: Void?
  101. private var imageTaskKey: Void?
  102. extension NSButton {
  103. /// Get the image URL binded to this image view.
  104. public var kf_webURL: NSURL? {
  105. return objc_getAssociatedObject(self, &lastURLKey) as? NSURL
  106. }
  107. private func kf_setWebURL(URL: NSURL) {
  108. objc_setAssociatedObject(self, &lastURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  109. }
  110. private var kf_imageTask: RetrieveImageTask? {
  111. return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask
  112. }
  113. private func kf_setImageTask(task: RetrieveImageTask?) {
  114. objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  115. }
  116. }
  117. /**
  118. * Set alternate image to use from web.
  119. */
  120. extension NSButton {
  121. /**
  122. Set an alternateImage with a URL, a placeholder image, options, progress handler and completion handler.
  123. - parameter URL: The URL of image.
  124. - parameter placeholderImage: A placeholder image when retrieving the image at URL.
  125. - parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
  126. - parameter progressBlock: Called when the image downloading progress gets updated.
  127. - parameter completionHandler: Called when the image retrieved and set.
  128. - returns: A task represents the retrieving process.
  129. - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
  130. The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
  131. */
  132. public func kf_setAlternateImageWithURL(URL: NSURL,
  133. placeholderImage: Image? = nil,
  134. optionsInfo: KingfisherOptionsInfo? = nil,
  135. progressBlock: DownloadProgressBlock? = nil,
  136. completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
  137. {
  138. return kf_setAlternateImageWithResource(Resource(downloadURL: URL),
  139. placeholderImage: placeholderImage,
  140. optionsInfo: optionsInfo,
  141. progressBlock: progressBlock,
  142. completionHandler: completionHandler)
  143. }
  144. /**
  145. Set an alternateImage with a URL, a placeholder image, options, progress handler and completion handler.
  146. - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
  147. - parameter placeholderImage: A placeholder image when retrieving the image at URL.
  148. - parameter optionsInfo: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
  149. - parameter progressBlock: Called when the image downloading progress gets updated.
  150. - parameter completionHandler: Called when the image retrieved and set.
  151. - returns: A task represents the retrieving process.
  152. - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
  153. The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
  154. */
  155. public func kf_setAlternateImageWithResource(resource: Resource,
  156. placeholderImage: Image? = nil,
  157. optionsInfo: KingfisherOptionsInfo? = nil,
  158. progressBlock: DownloadProgressBlock? = nil,
  159. completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
  160. {
  161. alternateImage = placeholderImage
  162. kf_setAlternateWebURL(resource.downloadURL)
  163. let task = KingfisherManager.sharedManager.retrieveImageWithResource(resource, optionsInfo: optionsInfo,
  164. progressBlock: { receivedSize, totalSize in
  165. if let progressBlock = progressBlock {
  166. progressBlock(receivedSize: receivedSize, totalSize: totalSize)
  167. }
  168. },
  169. completionHandler: {[weak self] image, error, cacheType, imageURL in
  170. dispatch_async_safely_to_main_queue {
  171. guard let sSelf = self where imageURL == sSelf.kf_alternateWebURL else {
  172. completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
  173. return
  174. }
  175. sSelf.kf_setAlternateImageTask(nil)
  176. guard let image = image else {
  177. completionHandler?(image: nil, error: error, cacheType: cacheType, imageURL: imageURL)
  178. return
  179. }
  180. sSelf.alternateImage = image
  181. completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL)
  182. }
  183. })
  184. kf_setImageTask(task)
  185. return task
  186. }
  187. }
  188. private var lastAlternateURLKey: Void?
  189. private var alternateImageTaskKey: Void?
  190. // MARK: - Runtime for NSButton alternateImage
  191. extension NSButton {
  192. /**
  193. Get the alternate image URL binded to this button.
  194. */
  195. public var kf_alternateWebURL: NSURL? {
  196. return objc_getAssociatedObject(self, &lastAlternateURLKey) as? NSURL
  197. }
  198. private func kf_setAlternateWebURL(URL: NSURL) {
  199. objc_setAssociatedObject(self, &lastAlternateURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  200. }
  201. private var kf_alternateImageTask: RetrieveImageTask? {
  202. return objc_getAssociatedObject(self, &alternateImageTaskKey) as? RetrieveImageTask
  203. }
  204. private func kf_setAlternateImageTask(task: RetrieveImageTask?) {
  205. objc_setAssociatedObject(self, &alternateImageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  206. }
  207. }
  208. // MARK: - Cancel image download tasks.
  209. extension NSButton {
  210. /**
  211. Cancel the image download task bounded to the image view if it is running.
  212. Nothing will happen if the downloading has already finished.
  213. */
  214. public func kf_cancelImageDownloadTask() {
  215. kf_imageTask?.downloadTask?.cancel()
  216. }
  217. public func kf_cancelAlternateImageDownloadTask() {
  218. kf_imageTask?.downloadTask?.cancel()
  219. }
  220. }