Просмотр исходного кода

Merge pull request #674 from onevcat/feature/default-option

Add default option property in KingfisherManager
Wei Wang 8 лет назад
Родитель
Сommit
12b54d6860

+ 0 - 1
Sources/ImageCache.swift

@@ -303,7 +303,6 @@ open class ImageCache {
                                         cacheSerializer: options.cacheSerializer,
                                         toDisk: false,
                                         completionHandler: nil)
-                            
                             options.callbackDispatchQueue.safeAsync {
                                 completionHandler(result, .memory)
                                 sSelf = nil

+ 11 - 20
Sources/ImageDownloader.swift

@@ -259,6 +259,7 @@ open class ImageDownloader {
      Download an image with a URL and option.
      
      - parameter url:               Target URL.
+     - parameter retrieveImageTask: The task to cooporate with cache. Pass `nil` if you are not trying to use downloader and cache.
      - parameter options:           The options could control download behavior. See `KingfisherOptionsInfo`.
      - parameter progressBlock:     Called when the download progress updated.
      - parameter completionHandler: Called when the download progress finishes.
@@ -267,25 +268,10 @@ open class ImageDownloader {
      */
     @discardableResult
     open func downloadImage(with url: URL,
-                            options: KingfisherOptionsInfo? = nil,
-                            progressBlock: ImageDownloaderProgressBlock? = nil,
-                            completionHandler: ImageDownloaderCompletionHandler? = nil) -> RetrieveImageDownloadTask?
-    {
-        return downloadImage(with: url,
-                             retrieveImageTask: nil,
-                             options: options,
-                             progressBlock: progressBlock,
-                             completionHandler: completionHandler)
-    }
-}
-
-// MARK: - Download method
-extension ImageDownloader {
-    func downloadImage(with url: URL,
-              retrieveImageTask: RetrieveImageTask?,
-                        options: KingfisherOptionsInfo?,
-                  progressBlock: ImageDownloaderProgressBlock?,
-              completionHandler: ImageDownloaderCompletionHandler?) -> RetrieveImageDownloadTask?
+                       retrieveImageTask: RetrieveImageTask? = nil,
+                       options: KingfisherOptionsInfo? = nil,
+                       progressBlock: ImageDownloaderProgressBlock? = nil,
+                       completionHandler: ImageDownloaderCompletionHandler? = nil) -> RetrieveImageDownloadTask?
     {
         if let retrieveImageTask = retrieveImageTask, retrieveImageTask.cancelledBeforeDownloadStarting {
             completionHandler?(nil, NSError(domain: KingfisherErrorDomain, code: KingfisherError.downloadCancelledBeforeStarting.rawValue, userInfo: nil), nil, nil)
@@ -318,7 +304,7 @@ extension ImageDownloader {
                 let dataTask = session.dataTask(with: request)
                 
                 fetchLoad.downloadTask = RetrieveImageDownloadTask(internalTask: dataTask, ownerDownloader: self)
-
+                
                 dataTask.priority = options?.downloadPriority ?? URLSessionTask.defaultPriority
                 dataTask.resume()
                 delegate?.imageDownloader(self, willDownloadImageForURL: url, with: request)
@@ -335,6 +321,11 @@ extension ImageDownloader {
         return downloadTask
     }
     
+}
+
+// MARK: - Download method
+extension ImageDownloader {
+    
     // A single key may have multiple callbacks. Only download once.
     func setup(progressBlock: ImageDownloaderProgressBlock?, with completionHandler: ImageDownloaderCompletionHandler?, for url: URL, options: KingfisherOptionsInfo?, started: ((URLSession, ImageFetchLoad) -> Void)) {
 

+ 2 - 2
Sources/ImageView+Kingfisher.swift

@@ -67,7 +67,7 @@ extension Kingfisher where Base: ImageView {
             return .empty
         }
         
-        var options = options ?? KingfisherEmptyOptionsInfo
+        var options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
         
         if !options.keepCurrentImageWhileLoading {
             base.image = placeholder
@@ -107,7 +107,7 @@ extension Kingfisher where Base: ImageView {
                         return
                     }
                     
-                    guard let transitionItem = options.firstMatchIgnoringAssociatedValue(.transition(.none)),
+                    guard let transitionItem = options.lastMatchIgnoringAssociatedValue(.transition(.none)),
                         case .transition(let transition) = transitionItem, ( options.forceTransition || cacheType == .none) else
                     {
                         maybeIndicator?.stopAnimatingView()

+ 15 - 7
Sources/KingfisherManager.swift

@@ -79,6 +79,15 @@ public class KingfisherManager {
     /// Downloader used by this manager
     public var downloader: ImageDownloader
     
+    /// Default options used by the manager. This option will be used in 
+    /// Kingfisher manager related methods, including all image view and 
+    /// button extension methods. You can also passing the options per image by 
+    /// sending an `options` parameter to Kingfisher's APIs, the per image option 
+    /// will overwrite the default ones if exist.
+    ///
+    /// - Note: This option will not be applied to independent using of `ImageDownloader` or `ImageCache`.
+    public var defaultOptions = KingfisherEmptyOptionsInfo
+    
     convenience init() {
         self.init(downloader: .default, cache: .default)
     }
@@ -108,8 +117,8 @@ public class KingfisherManager {
         completionHandler: CompletionHandler?) -> RetrieveImageTask
     {
         let task = RetrieveImageTask()
-
-        if let options = options, options.forceRefresh {
+        let options = defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
+        if options.forceRefresh {
             _ = downloadAndCacheImage(
                 with: resource.downloadURL,
                 forKey: resource.cacheKey,
@@ -136,9 +145,8 @@ public class KingfisherManager {
                       retrieveImageTask: RetrieveImageTask,
                           progressBlock: DownloadProgressBlock?,
                       completionHandler: CompletionHandler?,
-                                options: KingfisherOptionsInfo?) -> RetrieveImageDownloadTask?
+                                options: KingfisherOptionsInfo) -> RetrieveImageDownloadTask?
     {
-        let options = options ?? KingfisherEmptyOptionsInfo
         let downloader = options.downloader
         return downloader.downloadImage(with: url, retrieveImageTask: retrieveImageTask, options: options,
             progressBlock: { receivedSize, totalSize in
@@ -176,18 +184,18 @@ public class KingfisherManager {
                               retrieveImageTask: RetrieveImageTask,
                                   progressBlock: DownloadProgressBlock?,
                               completionHandler: CompletionHandler?,
-                                        options: KingfisherOptionsInfo?)
+                                        options: KingfisherOptionsInfo)
     {
         let diskTaskCompletionHandler: CompletionHandler = { (image, error, cacheType, imageURL) -> () in
             completionHandler?(image, error, cacheType, imageURL)
         }
         
-        let targetCache = options?.targetCache ?? cache
+        let targetCache = options.targetCache
         targetCache.retrieveImage(forKey: key, options: options,
             completionHandler: { image, cacheType in
                 if image != nil {
                     diskTaskCompletionHandler(image, nil, cacheType, url)
-                } else if let options = options, options.onlyFromCache {
+                } else if options.onlyFromCache {
                     let error = NSError(domain: KingfisherErrorDomain, code: KingfisherError.notCached.rawValue, userInfo: nil)
                     diskTaskCompletionHandler(nil, error, .none, url)
                 } else {

+ 18 - 16
Sources/KingfisherOptionsInfo.swift

@@ -152,20 +152,22 @@ func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Boo
     }
 }
 
-extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
-    func firstMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
-        return index { $0 <== target }.flatMap { self[$0] }
+extension Array where Element == KingfisherOptionsInfoItem {
+    
+    func lastMatchIgnoringAssociatedValue(_ target: Element) -> Element? {
+        return reversed().index { $0 <== target }
+            .flatMap { self[self.count - $0 - 1] }
     }
     
-    func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
-        return self.filter { !($0 <== target) }
+    func removeAllMatchesIgnoringAssociatedValue(_ target: Element) -> [Element] {
+        return filter { !($0 <== target) }
     }
 }
 
-public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
+public extension Array where Element == KingfisherOptionsInfoItem {
     /// The target `ImageCache` which is used.
     public var targetCache: ImageCache {
-        if let item = firstMatchIgnoringAssociatedValue(.targetCache(.default)),
+        if let item = lastMatchIgnoringAssociatedValue(.targetCache(.default)),
             case .targetCache(let cache) = item
         {
             return cache
@@ -175,7 +177,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// The `ImageDownloader` which is specified.
     public var downloader: ImageDownloader {
-        if let item = firstMatchIgnoringAssociatedValue(.downloader(.default)),
+        if let item = lastMatchIgnoringAssociatedValue(.downloader(.default)),
             case .downloader(let downloader) = item
         {
             return downloader
@@ -185,7 +187,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// Member for animation transition when using UIImageView.
     public var transition: ImageTransition {
-        if let item = firstMatchIgnoringAssociatedValue(.transition(.none)),
+        if let item = lastMatchIgnoringAssociatedValue(.transition(.none)),
             case .transition(let transition) = item
         {
             return transition
@@ -196,7 +198,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     /// A `Float` value set as the priority of image download task. The value for it should be
     /// between 0.0~1.0.
     public var downloadPriority: Float {
-        if let item = firstMatchIgnoringAssociatedValue(.downloadPriority(0)),
+        if let item = lastMatchIgnoringAssociatedValue(.downloadPriority(0)),
             case .downloadPriority(let priority) = item
         {
             return priority
@@ -236,7 +238,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// The queue of callbacks should happen from Kingfisher.
     public var callbackDispatchQueue: DispatchQueue {
-        if let item = firstMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
+        if let item = lastMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
             case .callbackDispatchQueue(let queue) = item
         {
             return queue ?? DispatchQueue.main
@@ -246,7 +248,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// The scale factor which should be used for the image.
     public var scaleFactor: CGFloat {
-        if let item = firstMatchIgnoringAssociatedValue(.scaleFactor(0)),
+        if let item = lastMatchIgnoringAssociatedValue(.scaleFactor(0)),
             case .scaleFactor(let scale) = item
         {
             return scale
@@ -256,7 +258,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// The `ImageDownloadRequestModifier` will be used before sending a download request.
     public var modifier: ImageDownloadRequestModifier {
-        if let item = firstMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
+        if let item = lastMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
             case .requestModifier(let modifier) = item
         {
             return modifier
@@ -266,7 +268,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// `ImageProcessor` for processing when the downloading finishes.
     public var processor: ImageProcessor {
-        if let item = firstMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
+        if let item = lastMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
             case .processor(let processor) = item
         {
             return processor
@@ -276,7 +278,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
     
     /// `CacheSerializer` to convert image to data for storing in cache.
     public var cacheSerializer: CacheSerializer {
-        if let item = firstMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
+        if let item = lastMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
             case .cacheSerializer(let cacheSerializer) = item
         {
             return cacheSerializer
@@ -296,7 +298,7 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem
 }
 
 // MARK: - Deprecated. Only for back compatibility.
-public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
+public extension Array where Element == KingfisherOptionsInfoItem {
 
     /// Whether the image data should be all loaded at once if it is a GIF.
     @available(*, deprecated, renamed: "preloadAllAnimationData")

+ 2 - 2
Sources/NSButton+Kingfisher.swift

@@ -63,7 +63,7 @@ extension Kingfisher where Base: NSButton {
             return .empty
         }
         
-        let options = options ?? KingfisherEmptyOptionsInfo
+        let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
         if !options.keepCurrentImageWhileLoading {
             base.image = placeholder
         }
@@ -138,7 +138,7 @@ extension Kingfisher where Base: NSButton {
             return .empty
         }
         
-        let options = options ?? KingfisherEmptyOptionsInfo
+        let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
         if !options.keepCurrentImageWhileLoading {
             base.alternateImage = placeholder
         }

+ 2 - 2
Sources/UIButton+Kingfisher.swift

@@ -65,7 +65,7 @@ extension Kingfisher where Base: UIButton {
             return .empty
         }
         
-        let options = options ?? KingfisherEmptyOptionsInfo
+        let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
         if !options.keepCurrentImageWhileLoading {
             base.setImage(placeholder, for: state)
         }
@@ -143,7 +143,7 @@ extension Kingfisher where Base: UIButton {
             return .empty
         }
         
-        let options = options ?? KingfisherEmptyOptionsInfo
+        let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
         if !options.keepCurrentImageWhileLoading {
             base.setBackgroundImage(placeholder, for: state)
         }

+ 7 - 1
Tests/KingfisherTests/ImageViewExtensionTests.swift

@@ -535,7 +535,7 @@ class ImageViewExtensionTests: XCTestCase {
     }
     
     func testSettingImageWhileKeepingCurrentOne() {
-
+        let expectation = self.expectation(description: "wait for downloading image")
         let URLString = testKeys[0]
         _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
         let url = URL(string: URLString)!
@@ -547,6 +547,12 @@ class ImageViewExtensionTests: XCTestCase {
         imageView.image = testImage
         imageView.kf.setImage(with: url, placeholder: nil, options: [.keepCurrentImageWhileLoading])
         XCTAssertEqual(testImage, imageView.image)
+        
+        // Wait request finished. Ensure tests timing order.
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { 
+            expectation.fulfill()
+        }
+        waitForExpectations(timeout: 5, handler: nil)
     }
     
     func testSetGIFImageOnlyFirstFrameThenFullFrames() {

+ 17 - 0
Tests/KingfisherTests/KingfisherManagerTests.swift

@@ -276,4 +276,21 @@ class KingfisherManagerTests: XCTestCase {
         })
         waitForExpectations(timeout: 5, handler: nil)
     }
+    
+    func testDefaultOptionCouldApply() {
+        let expectation = self.expectation(description: "running on custom queue")
+        let URLString = testKeys[0]
+        _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
+        
+        let url = URL(string: URLString)!
+        
+        manager.defaultOptions = [.scaleFactor(2)]
+        manager.retrieveImage(with: url, options: nil, progressBlock: nil, completionHandler: { image, _, _, _ in
+            #if !os(macOS)
+            XCTAssertEqual(image!.scale, 2.0)
+            #endif
+            expectation.fulfill()
+        })
+        waitForExpectations(timeout: 5, handler: nil)
+    }
 }

+ 11 - 0
Tests/KingfisherTests/KingfisherOptionsInfoTests.swift

@@ -117,6 +117,17 @@ class KingfisherOptionsInfoTests: XCTestCase {
         XCTAssertTrue(options.keepCurrentImageWhileLoading)
         XCTAssertTrue(options.onlyLoadFirstFrame)
     }
+    
+    func testOptionCouldBeOverwritten() {
+        var options: KingfisherOptionsInfo = [.downloadPriority(0.5), .onlyFromCache]
+        XCTAssertEqual(options.downloadPriority, 0.5)
+        
+        options.append(.downloadPriority(0.8))
+        XCTAssertEqual(options.downloadPriority, 0.8)
+        
+        options.append(.downloadPriority(1.0))
+        XCTAssertEqual(options.downloadPriority, 1.0)
+    }
 }
 
 class TestModifier: ImageDownloadRequestModifier {