UIImageView+Haneke.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. //
  2. // UIImageView+Haneke.swift
  3. // Haneke
  4. //
  5. // Created by Hermes Pique on 9/17/14.
  6. // Copyright (c) 2014 Haneke. All rights reserved.
  7. //
  8. import UIKit
  9. public extension UIImageView {
  10. public var hnk_format : Format<UIImage> {
  11. let viewSize = self.bounds.size
  12. assert(viewSize.width > 0 && viewSize.height > 0, "[\(Mirror(reflecting: self).description) \(#function)]: UImageView size is zero. Set its frame, call sizeToFit or force layout first.")
  13. let scaleMode = self.hnk_scaleMode
  14. return HanekeGlobals.UIKit.formatWithSize(viewSize, scaleMode: scaleMode)
  15. }
  16. public func hnk_setImageFromURL(_ URL: Foundation.URL, placeholder : UIImage? = nil, format : Format<UIImage>? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) {
  17. let fetcher = NetworkFetcher<UIImage>(URL: URL)
  18. self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, failure: fail, success: succeed)
  19. }
  20. public func hnk_setImage( _ image: @autoclosure @escaping () -> UIImage, key: String, placeholder : UIImage? = nil, format : Format<UIImage>? = nil, success succeed : ((UIImage) -> ())? = nil) {
  21. let fetcher = SimpleFetcher<UIImage>(key: key, value: image())
  22. self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, success: succeed)
  23. }
  24. public func hnk_setImageFromFile(_ path: String, placeholder : UIImage? = nil, format : Format<UIImage>? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) {
  25. let fetcher = DiskFetcher<UIImage>(path: path)
  26. self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, failure: fail, success: succeed)
  27. }
  28. public func hnk_setImage(fromFetcher fetcher : Fetcher<UIImage>,
  29. placeholder : UIImage? = nil,
  30. format : Format<UIImage>? = nil,
  31. failure fail : ((Error?) -> ())? = nil,
  32. success succeed : ((UIImage) -> ())? = nil) {
  33. self.hnk_cancelSetImage()
  34. self.hnk_fetcher = fetcher
  35. let didSetImage = self.hnk_fetchImageForFetcher(fetcher, format: format, failure: fail, success: succeed)
  36. if didSetImage { return }
  37. if let placeholder = placeholder {
  38. self.image = placeholder
  39. }
  40. }
  41. public func hnk_cancelSetImage() {
  42. if let fetcher = self.hnk_fetcher {
  43. fetcher.cancelFetch()
  44. self.hnk_fetcher = nil
  45. }
  46. }
  47. // MARK: Internal
  48. // See: http://stackoverflow.com/questions/25907421/associating-swift-things-with-nsobject-instances
  49. var hnk_fetcher : Fetcher<UIImage>! {
  50. get {
  51. let wrapper = objc_getAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey) as? ObjectWrapper
  52. let fetcher = wrapper?.hnk_value as? Fetcher<UIImage>
  53. return fetcher
  54. }
  55. set (fetcher) {
  56. var wrapper : ObjectWrapper?
  57. if let fetcher = fetcher {
  58. wrapper = ObjectWrapper(value: fetcher)
  59. }
  60. objc_setAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  61. }
  62. }
  63. public var hnk_scaleMode : ImageResizer.ScaleMode {
  64. switch (self.contentMode) {
  65. case .scaleToFill:
  66. return .Fill
  67. case .scaleAspectFit:
  68. return .AspectFit
  69. case .scaleAspectFill:
  70. return .AspectFill
  71. case .redraw, .center, .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight:
  72. return .None
  73. }
  74. }
  75. func hnk_fetchImageForFetcher(_ fetcher : Fetcher<UIImage>, format : Format<UIImage>? = nil, failure fail : ((Error?) -> ())?, success succeed : ((UIImage) -> ())?) -> Bool {
  76. let cache = Shared.imageCache
  77. let format = format ?? self.hnk_format
  78. if cache.formats[format.name] == nil {
  79. cache.addFormat(format)
  80. }
  81. var animated = false
  82. let fetch = cache.fetch(fetcher: fetcher, formatName: format.name, failure: {[weak self] error in
  83. if let strongSelf = self {
  84. if strongSelf.hnk_shouldCancel(forKey: fetcher.key) { return }
  85. strongSelf.hnk_fetcher = nil
  86. fail?(error)
  87. }
  88. }) { [weak self] image in
  89. if let strongSelf = self {
  90. if strongSelf.hnk_shouldCancel(forKey: fetcher.key) { return }
  91. strongSelf.hnk_setImage(image, animated: animated, success: succeed)
  92. }
  93. }
  94. animated = true
  95. return fetch.hasSucceeded
  96. }
  97. func hnk_setImage(_ image : UIImage, animated : Bool, success succeed : ((UIImage) -> ())?) {
  98. self.hnk_fetcher = nil
  99. if let succeed = succeed {
  100. succeed(image)
  101. } else if animated {
  102. UIView.transition(with: self, duration: HanekeGlobals.UIKit.SetImageAnimationDuration, options: .transitionCrossDissolve, animations: {
  103. self.image = image
  104. }, completion: nil)
  105. } else {
  106. self.image = image
  107. }
  108. }
  109. func hnk_shouldCancel(forKey key:String) -> Bool {
  110. if self.hnk_fetcher?.key == key { return false }
  111. //Log.debug(message: "Cancelled set image for \((key as NSString).lastPathComponent)")
  112. return true
  113. }
  114. }