Kaynağa Gözat

Use source for image view extension

onevcat 7 yıl önce
ebeveyn
işleme
aa64d9c49f

+ 63 - 47
Sources/Extensions/ImageView+Kingfisher.swift

@@ -33,45 +33,21 @@ import UIKit
 
 extension KingfisherClass where Base: ImageView {
 
-    /// Sets an image to the image view with a requested resource.
-    ///
-    /// - Parameters:
-    ///   - resource: The `Resource` object contains information about the resource.
-    ///   - placeholder: A placeholder to show while retrieving the image from the given `resource`.
-    ///   - options: An options set to define image setting behaviors. See `KingfisherOptionsInfo` for more.
-    ///   - progressBlock: Called when the image downloading progress gets updated. If the response does not contain an
-    ///                    `expectedContentLength`, this block will not be called.
-    ///   - completionHandler: Called when the image retrieved and set finished.
-    /// - Returns: A task represents the image downloading.
-    ///
-    /// - Note:
-    /// This is the easist way to use Kingfisher to boost the image setting process from network. Since all parameters
-    /// have a default value except the `resource`, you can set an image from a certain URL to an image view like this:
-    ///
-    /// ```
-    /// let url = URL(string: "https://example.com/image.png")!
-    /// imageView.kf.setImage(with: URL(string: url))
-    /// ```
-    ///
-    /// Internally, this method will use `KingfisherManager` to get the requested resource, from either cache
-    /// or network. Since this method will perform UI changes, you must call it from the main thread.
-    /// Both `progressBlock` and `completionHandler` will be also executed in the main thread.
-    ///
     @discardableResult
-    public func setImage(with resource: Resource?,
+    public func setImage(with source: Source?,
                          placeholder: Placeholder? = nil,
                          options: KingfisherOptionsInfo? = nil,
                          progressBlock: DownloadProgressBlock? = nil,
                          completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)? = nil)
         -> DownloadTask?
     {
-        guard let resource = resource else {
+        guard let source = source else {
             self.placeholder = placeholder
-            webURL = nil
+            taskIdentifier = nil
             completionHandler?(.failure(KingfisherError.imageSettingError(reason: .emptyResource)))
             return nil
         }
-        
+
         var options = KingfisherManager.shared.defaultOptions + (options ?? .empty)
         let noImageOrPlaceholderSet = base.image == nil && self.placeholder == nil
         if !options.keepCurrentImageWhileLoading || noImageOrPlaceholderSet {
@@ -82,27 +58,27 @@ extension KingfisherClass where Base: ImageView {
         let maybeIndicator = indicator
         maybeIndicator?.startAnimatingView()
 
-        webURL = resource.downloadURL
+        taskIdentifier = source.identifier
 
         if base.shouldPreloadAllAnimation() {
             options.append(.preloadAllAnimationData)
         }
-        
+
         let task = KingfisherManager.shared.retrieveImage(
-            with: resource,
+            with: source,
             options: options,
             progressBlock: { receivedSize, totalSize in
-                guard resource.downloadURL == self.webURL else { return }
+                guard source.identifier == self.taskIdentifier else { return }
                 if let progressBlock = progressBlock {
                     progressBlock(receivedSize, totalSize)
                 }
-            },
+        },
             completionHandler: { result in
-                DispatchQueue.main.safeAsync {
+                CallbackQueue.mainCurrentOrAsync.execute {
                     maybeIndicator?.stopAnimatingView()
-                    guard resource.downloadURL == self.webURL else {
+                    guard source.identifier == self.taskIdentifier else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, source: source))
                         completionHandler?(.failure(error))
                         return
                     }
@@ -111,7 +87,7 @@ extension KingfisherClass where Base: ImageView {
 
                     switch result {
                     case .success(let value):
-                        
+
                         #if !os(macOS)
                         guard self.needsTransition(options: options, cacheType: value.cacheType) else {
                             self.placeholder = nil
@@ -119,7 +95,7 @@ extension KingfisherClass where Base: ImageView {
                             completionHandler?(result)
                             return
                         }
-                        
+
                         let transition = options.transition
 
                         // Force hiding the indicator without transition first.
@@ -138,9 +114,9 @@ extension KingfisherClass where Base: ImageView {
                                     completion: { finished in
                                         transition.completion?(finished)
                                         completionHandler?(result)
-                                    }
+                                }
                                 )
-                            }
+                        }
                         )
                         #else
                         self.placeholder = nil
@@ -155,11 +131,52 @@ extension KingfisherClass where Base: ImageView {
                     }
                 }
         })
-        
+
         imageTask = task
         return task
     }
 
+
+    /// Sets an image to the image view with a requested resource.
+    ///
+    /// - Parameters:
+    ///   - resource: The `Resource` object contains information about the resource.
+    ///   - placeholder: A placeholder to show while retrieving the image from the given `resource`.
+    ///   - options: An options set to define image setting behaviors. See `KingfisherOptionsInfo` for more.
+    ///   - progressBlock: Called when the image downloading progress gets updated. If the response does not contain an
+    ///                    `expectedContentLength`, this block will not be called.
+    ///   - completionHandler: Called when the image retrieved and set finished.
+    /// - Returns: A task represents the image downloading.
+    ///
+    /// - Note:
+    /// This is the easist way to use Kingfisher to boost the image setting process from network. Since all parameters
+    /// have a default value except the `resource`, you can set an image from a certain URL to an image view like this:
+    ///
+    /// ```
+    /// let url = URL(string: "https://example.com/image.png")!
+    /// imageView.kf.setImage(with: URL(string: url))
+    /// ```
+    ///
+    /// Internally, this method will use `KingfisherManager` to get the requested resource, from either cache
+    /// or network. Since this method will perform UI changes, you must call it from the main thread.
+    /// Both `progressBlock` and `completionHandler` will be also executed in the main thread.
+    ///
+    @discardableResult
+    public func setImage(with resource: Resource?,
+                         placeholder: Placeholder? = nil,
+                         options: KingfisherOptionsInfo? = nil,
+                         progressBlock: DownloadProgressBlock? = nil,
+                         completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)? = nil)
+        -> DownloadTask?
+    {
+        return setImage(
+            with: resource.map { .network($0) },
+            placeholder: placeholder,
+            options: options,
+            progressBlock: progressBlock,
+            completionHandler: completionHandler)
+    }
+
     /// Cancels the image download task of the image view if it is running.
     /// Nothing will happen if the downloading has already finished.
     public func cancelDownloadTask() {
@@ -183,18 +200,17 @@ extension KingfisherClass where Base: ImageView {
 }
 
 // MARK: - Associated Object
-private var lastURLKey: Void?
+private var taskIdentifierKey: Void?
 private var indicatorKey: Void?
 private var indicatorTypeKey: Void?
 private var placeholderKey: Void?
 private var imageTaskKey: Void?
 
 extension KingfisherClass where Base: ImageView {
-    
-    /// Gets the image URL binded to this image view.
-    public private(set) var webURL: URL? {
-        get { return getAssociatedObject(base, &lastURLKey) }
-        set { setRetainedAssociatedObject(base, &lastURLKey, newValue) }
+
+    public internal(set) var taskIdentifier: String? {
+        get { return getAssociatedObject(base, &taskIdentifierKey) }
+        set { setRetainedAssociatedObject(base, &taskIdentifierKey, newValue) }
     }
 
     /// Holds which indicator type is going to be used.

+ 2 - 2
Sources/Extensions/NSButton+Kingfisher.swift

@@ -77,7 +77,7 @@ extension KingfisherClass where Base: NSButton {
                 DispatchQueue.main.safeAsync {
                     guard resource.downloadURL == self.webURL else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, source: .network(resource)))
                         completionHandler?(.failure(error))
                         return
                     }
@@ -155,7 +155,7 @@ extension KingfisherClass where Base: NSButton {
                 DispatchQueue.main.safeAsync {
                     guard resource.downloadURL == self.alternateWebURL else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, source: .network(resource)))
                         completionHandler?(.failure(error))
                         return
                     }

+ 2 - 2
Sources/Extensions/UIButton+Kingfisher.swift

@@ -78,7 +78,7 @@ extension KingfisherClass where Base: UIButton {
                 DispatchQueue.main.safeAsync {
                     guard resource.downloadURL == self.webURL(for: state) else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, source: .network(resource)))
                         completionHandler?(.failure(error))
                         return
                     }
@@ -162,7 +162,7 @@ extension KingfisherClass where Base: UIButton {
                 DispatchQueue.main.safeAsync {
                     guard resource.downloadURL == self.backgroundWebURL(for: state) else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, source: .network(resource)))
                         completionHandler?(.failure(error))
                         return
                     }

+ 1 - 1
Sources/Extensions/WKInterfaceImage+Kingfisher.swift

@@ -77,7 +77,7 @@ extension KingfisherClass where Base: WKInterfaceImage {
                 DispatchQueue.main.safeAsync {
                     guard resource.downloadURL == self.webURL else {
                         let error = KingfisherError.imageSettingError(
-                            reason: .notCurrentResource(result: result.value, error: result.error, resource: resource))
+                            reason: .notCurrentSource(result: result.value, error: result.error, resource: resource))
                         completionHandler?(.failure(error))
                         return
                     }

+ 9 - 0
Sources/General/Deprecated.swift

@@ -449,3 +449,12 @@ public let KingfisherErrorDomain = "com.onevcat.Kingfisher.Error"
 @available(*, unavailable,
 message: "Use `.invalidHTTPStatusCode` or `isInvalidResponseStatusCode` of `KingfisherError` instead for the status code.")
 public let KingfisherErrorStatusCodeKey = "statusCode"
+
+extension KingfisherClass where Base: ImageView {
+    /// Gets the image URL binded to this image view.
+    @available(*, deprecated, message: "Use `taskIdentifier` instead.", renamed: "taskIdentifier")
+    public private(set) var webURL: URL? {
+        get { return taskIdentifier.flatMap { URL(string: $0) } }
+        set { taskIdentifier = newValue?.absoluteString }
+    }
+}

+ 5 - 5
Sources/General/KingfisherError.swift

@@ -156,7 +156,7 @@ public enum KingfisherError: Error {
     /// Represnts the error reason duting image setting in a view related class.
     ///
     /// - emptyResource: The input resource is empty or `nil`. Code 5001.
-    /// - notCurrentResource: The resource task is finished, but it is not the one expected now. Code 5002.
+    /// - notCurrentSource: The source task is finished, but it is not the one expected now. Code 5002.
     /// - dataProviderError: An error happens during getting data from an `ImageDataProvider`. Code 5003.
     public enum ImageSettingErrorReason {
         
@@ -165,9 +165,9 @@ public enum KingfisherError: Error {
         
         /// The resource task is finished, but it is not the one expected now. This usually happens when you set another
         /// resource on the view without cancelling the current on-going one. The previous setting task will fail with
-        /// this `.notCurrentResource` error when a result got, regardless of it being successful or not for that task.
+        /// this `.notCurrentSource` error when a result got, regardless of it being successful or not for that task.
         /// Code 5002.
-        case notCurrentResource(result: RetrieveImageResult?, error: Error?, resource: Resource)
+        case notCurrentSource(result: RetrieveImageResult?, error: Error?, source: Source)
 
         /// An error happens during getting data from an `ImageDataProvider`. Code 5003.
         case dataProviderError(provider: ImageDataProvider, error: Error)
@@ -338,7 +338,7 @@ extension KingfisherError.ImageSettingErrorReason {
         switch self {
         case .emptyResource:
             return "The input resource is empty."
-        case .notCurrentResource(let result, let error, let resource):
+        case .notCurrentSource(let result, let error, let resource):
             if let result = result {
                 return "Retrieving resource succeeded, but this resource is " +
                        "not the one currently expected. Result: \(result). Resource: \(resource)."
@@ -356,7 +356,7 @@ extension KingfisherError.ImageSettingErrorReason {
     var errorCode: Int {
         switch self {
         case .emptyResource: return 5001
-        case .notCurrentResource: return 5002
+        case .notCurrentSource: return 5002
         case .dataProviderError: return 5003
         }
     }

+ 1 - 1
Sources/General/Resource.swift

@@ -61,7 +61,7 @@ public protocol Resource {
     /// The target image URL.
     var downloadURL: URL { get }
 
-    var identifier: String {get }
+    var identifier: String { get }
 }
 
 extension Resource {

+ 4 - 4
Tests/KingfisherTests/ImageViewExtensionTests.swift

@@ -80,7 +80,7 @@ class ImageViewExtensionTests: XCTestCase {
             let value = result.value!
             XCTAssertTrue(value.image.renderEqual(to: testImage))
             XCTAssertTrue(self.imageView.image!.renderEqual(to: testImage))
-            XCTAssertEqual(self.imageView.kf.webURL, url)
+            XCTAssertEqual(self.imageView.kf.taskIdentifier, url.absoluteString)
             
             XCTAssertEqual(value.cacheType, .none)
             XCTAssertTrue(Thread.isMainThread)
@@ -127,7 +127,7 @@ class ImageViewExtensionTests: XCTestCase {
             let value = result.value!
             XCTAssertTrue(value.image.renderEqual(to: testImage))
             XCTAssertTrue(self.imageView.image!.renderEqual(to: testImage))
-            XCTAssertEqual(self.imageView.kf.webURL, url)
+            XCTAssertEqual(self.imageView.kf.taskIdentifier, url.absoluteString)
 
             XCTAssertEqual(value.cacheType, .none)
             XCTAssertTrue(Thread.isMainThread)
@@ -364,9 +364,9 @@ class ImageViewExtensionTests: XCTestCase {
             // The download successed, but not the resource we want.
             XCTAssertNotNil(result.error)
             if case .imageSettingError(
-                reason: .notCurrentResource(let result, _, let resource)) = result.error!
+                reason: .notCurrentSource(let result, _, let source)) = result.error!
             {
-                XCTAssertEqual(resource.downloadURL, testURLs[0])
+                XCTAssertEqual(source.url, testURLs[0])
                 XCTAssertNotEqual(result!.image, self.imageView.image)
             } else {
                 XCTFail()