ソースを参照

Merge remote-tracking branch 'onevcat/master'

# Conflicts:
#	Tests/KingfisherTests/ImageCacheTests.swift
Claire Knight 10 年 前
コミット
1a24179190

+ 8 - 0
CHANGELOG.md

@@ -2,6 +2,14 @@
 
 -----
 
+## [2.0.4 - Sorry Pipelining](https://github.com/onevcat/Kingfisher/releases/tag/2.0.4) (2016-02-27)
+
+#### Fix
+* Make pipeling support to be disabled by default since it requiring server support. You can enable it by setting `requestsUsePipeling` in `ImageDownloader`. [#253](https://github.com/onevcat/Kingfisher/pull/253)
+* Image transition now allows user interaction. [#252](https://github.com/onevcat/Kingfisher/pull/252)
+
+---
+
 ## [2.0.3 - Holiday Issues](https://github.com/onevcat/Kingfisher/releases/tag/2.0.3) (2016-02-17)
 
 #### Fix

+ 2 - 2
Demo/Kingfisher-Demo/Info.plist

@@ -15,11 +15,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
 	<key>UILaunchStoryboardName</key>

+ 2 - 2
Demo/Kingfisher-OSX-Demo/Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>LSMinimumSystemVersion</key>
 	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
 	<key>NSHumanReadableCopyright</key>

+ 2 - 2
Demo/Kingfisher-tvOS-Demo/Info.plist

@@ -15,11 +15,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
 	<key>UIMainStoryboardFile</key>

+ 2 - 2
Demo/Kingfisher-watchOS-Demo Extension/Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>XPC!</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>NSExtension</key>
 	<dict>
 		<key>NSExtensionAttributes</key>

+ 2 - 2
Demo/Kingfisher-watchOS-Demo/Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>UISupportedInterfaceOrientations</key>
 	<array>
 		<string>UIInterfaceOrientationPortrait</string>

+ 1 - 1
Kingfisher.podspec

@@ -1,7 +1,7 @@
 Pod::Spec.new do |s|
 
   s.name         = "Kingfisher"
-  s.version      = "2.0.3"
+  s.version      = "2.0.4"
   s.summary      = "A lightweight and pure Swift implemented library for downloading and cacheing image from the web."
 
   s.description  = <<-DESC

+ 16 - 16
Kingfisher.xcodeproj/project.pbxproj

@@ -1503,11 +1503,11 @@
 			buildSettings = {
 				CODE_SIGN_IDENTITY = "";
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				FRAMEWORK_VERSION = A;
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -1529,11 +1529,11 @@
 			buildSettings = {
 				CODE_SIGN_IDENTITY = "";
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				FRAMEWORK_VERSION = A;
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -1695,11 +1695,11 @@
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_NO_COMMON_BLOCKS = YES;
 				INFOPLIST_FILE = Sources/Info.plist;
@@ -1722,11 +1722,11 @@
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_NO_COMMON_BLOCKS = YES;
 				INFOPLIST_FILE = Sources/Info.plist;
@@ -1747,11 +1747,11 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				APPLICATION_EXTENSION_API_ONLY = YES;
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_NO_COMMON_BLOCKS = YES;
 				INFOPLIST_FILE = Sources/Info.plist;
@@ -1772,11 +1772,11 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				APPLICATION_EXTENSION_API_ONLY = YES;
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_NO_COMMON_BLOCKS = YES;
 				INFOPLIST_FILE = Sources/Info.plist;
@@ -1979,10 +1979,10 @@
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				INFOPLIST_FILE = Sources/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -2003,10 +2003,10 @@
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 536;
+				CURRENT_PROJECT_VERSION = 543;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 536;
+				DYLIB_CURRENT_VERSION = 543;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				INFOPLIST_FILE = Sources/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";

+ 17 - 17
Sources/ImageCache.swift

@@ -279,18 +279,8 @@ extension ImageCache {
         let options = options ?? KingfisherEmptyOptionsInfo
         
         if let image = self.retrieveImageInMemoryCacheForKey(key) {
-            //Found image in memory cache.
-            if options.backgroundDecode {
-                dispatch_async(self.processQueue, { () -> Void in
-                    let result = image.kf_decodedImage(scale: options.scaleFactor)
-                    dispatch_async_safely_to_queue(options.callbackDispatchQueue, { () -> Void in
-                        completionHandler(result, .Memory)
-                    })
-                })
-            } else {
-                dispatch_async_safely_to_queue(options.callbackDispatchQueue, { () -> Void in
-                    completionHandler(image, .Memory)
-                })
+            dispatch_async_safely_to_queue(options.callbackDispatchQueue) { () -> Void in
+                completionHandler(image, .Memory)
             }
         } else {
             var sSelf: ImageCache! = self
@@ -619,6 +609,21 @@ extension ImageCache {
             })
         })
     }
+    
+    /**
+    Get the cache path for the key.
+    It is useful for projects with UIWebView or anyone that needs access to the local file path.
+    
+    i.e. `<img src='path_for_key'>`
+     
+    - Note: This method does not guarantee there is an image already cached in the path. 
+      You could use `isImageCachedForKey` method to check whether the image is cached under that key.
+    */
+    public func cachePathForKey(key: String) -> String {
+        let fileName = cacheFileNameForKey(key)
+        return (diskCachePath as NSString).stringByAppendingPathComponent(fileName)
+    }
+
 }
 
 // MARK: - Internal Helper
@@ -637,11 +642,6 @@ extension ImageCache {
         return NSData(contentsOfFile: filePath)
     }
     
-    func cachePathForKey(key: String) -> String {
-        let fileName = cacheFileNameForKey(key)
-        return (diskCachePath as NSString).stringByAppendingPathComponent(fileName)
-    }
-    
     func cacheFileNameForKey(key: String) -> String {
         return key.kf_MD5
     }

+ 49 - 15
Sources/ImageDownloader.swift

@@ -101,6 +101,37 @@ public enum KingfisherError: Int {
     optional func imageDownloader(downloader: ImageDownloader, didDownloadImage image: Image, forURL URL: NSURL, withResponse response: NSURLResponse)
 }
 
+/// Protocol indicates that an authentication challenge could be handled.
+public protocol AuthenticationChallengeResponable: class {
+    /**
+     Called when an session level authentication challenge is received.
+     This method provide a chance to handle and response to the authentication challenge before downloading could start.
+     
+     - parameter downloader:        The downloader which receives this challenge.
+     - parameter challenge:         An object that contains the request for authentication.
+     - parameter completionHandler: A handler that your delegate method must call.
+     
+     - Note: This method is a forward from `URLSession(:didReceiveChallenge:completionHandler:)`. Please refer to the document of it in `NSURLSessionDelegate`.
+     */
+    func downloder(downloader: ImageDownloader, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
+}
+
+extension AuthenticationChallengeResponable {
+    
+    func downloder(downloader: ImageDownloader, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
+    
+        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+            if let trustedHosts = downloader.trustedHosts where trustedHosts.contains(challenge.protectionSpace.host) {
+                let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
+                completionHandler(.UseCredential, credential)
+                return
+            }
+        }
+        
+        completionHandler(.PerformDefaultHandling, nil)
+    }
+}
+
 /// `ImageDownloader` represents a downloading manager for requesting the image with a URL from server.
 public class ImageDownloader: NSObject {
     
@@ -121,7 +152,7 @@ public class ImageDownloader: NSObject {
     /// The duration before the download is timeout. Default is 15 seconds.
     public var downloadTimeout: NSTimeInterval = 15.0
     
-    /// A set of trusted hosts when receiving server trust challenges. A challenge with host name contained in this set will be ignored. You can use this set to specify the self-signed site.
+    /// A set of trusted hosts when receiving server trust challenges. A challenge with host name contained in this set will be ignored. You can use this set to specify the self-signed site. It only will be used if you don't specify the `authenticationChallengeResponder`. If `authenticationChallengeResponder` is set, this property will be ignored and the implemention of `authenticationChallengeResponder` will be used instead.
     public var trustedHosts: Set<String>?
     
     /// Use this to set supply a configuration for the downloader. By default, NSURLSessionConfiguration.ephemeralSessionConfiguration() will be used. You could change the configuration before a downloaing task starts. A configuration without persistent storage for caches is requsted for downloader working correctly.
@@ -131,12 +162,19 @@ public class ImageDownloader: NSObject {
         }
     }
     
-    private var sessionHandler: ImageDownloaderSessionHandler?
+    /// Whether the download requests should use pipeling or not. Default is false.
+    public var requestsUsePipeling = false
+    
+    private let sessionHandler: ImageDownloaderSessionHandler
     private var session: NSURLSession?
     
     /// Delegate of this `ImageDownloader` object. See `ImageDownloaderDelegate` protocol for more.
     public weak var delegate: ImageDownloaderDelegate?
     
+    /// A responder for authentication challenge. 
+    /// Downloader will forward the received authentication challenge for the downloading session to this responder.
+    public weak var authenticationChallengeResponder: AuthenticationChallengeResponable?
+    
     // MARK: - Internal property
     let barrierQueue: dispatch_queue_t
     let processQueue: dispatch_queue_t
@@ -166,9 +204,13 @@ public class ImageDownloader: NSObject {
         barrierQueue = dispatch_queue_create(downloaderBarrierName + name, DISPATCH_QUEUE_CONCURRENT)
         processQueue = dispatch_queue_create(imageProcessQueueName + name, DISPATCH_QUEUE_CONCURRENT)
         
+        sessionHandler = ImageDownloaderSessionHandler()
+        
         super.init()
         
-        sessionHandler = ImageDownloaderSessionHandler()
+        // Provide a default implement for challenge responder.
+        authenticationChallengeResponder = sessionHandler
+        
         session = NSURLSession(configuration: sessionConfiguration, delegate: sessionHandler, delegateQueue: NSOperationQueue.mainQueue())
     }
     
@@ -235,7 +277,7 @@ extension ImageDownloader {
         
         // We need to set the URL as the load key. So before setup progress, we need to ask the `requestModifier` for a final URL.
         let request = NSMutableURLRequest(URL: URL, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: timeout)
-        request.HTTPShouldUsePipelining = true
+        request.HTTPShouldUsePipelining = requestsUsePipeling
         
         self.requestModifier?(request)
         
@@ -257,7 +299,7 @@ extension ImageDownloader {
                 dataTask.resume()
                 
                 // Hold self while the task is executing.
-                self.sessionHandler?.downloadHolder = self
+                self.sessionHandler.downloadHolder = self
             }
             
             fetchLoad.downloadTaskCount += 1
@@ -312,7 +354,7 @@ extension ImageDownloader {
 /// The session object will hold its delegate until it gets invalidated.
 /// If we use `ImageDownloader` as the session delegate, it will not be released.
 /// So we need an additional handler to break the retain cycle.
-class ImageDownloaderSessionHandler: NSObject, NSURLSessionDataDelegate {
+class ImageDownloaderSessionHandler: NSObject, NSURLSessionDataDelegate, AuthenticationChallengeResponable {
     
     // The holder will keep downloader not released while a data task is being executed.
     // It will be set when the task started, and reset when the task finished.
@@ -369,15 +411,7 @@ class ImageDownloaderSessionHandler: NSObject, NSURLSessionDataDelegate {
             return
         }
         
-        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
-            if let trustedHosts = downloader.trustedHosts where trustedHosts.contains(challenge.protectionSpace.host) {
-                let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
-                completionHandler(.UseCredential, credential)
-                return
-            }
-        }
-        
-        completionHandler(.PerformDefaultHandling, nil)
+        downloader.authenticationChallengeResponder?.downloder(downloader, didReceiveChallenge: challenge, completionHandler: completionHandler)
     }
     
     private func callbackWithImage(image: Image?, error: NSError?, imageURL: NSURL, originalData: NSData?) {

+ 1 - 1
Sources/ImageView+Kingfisher.swift

@@ -236,7 +236,7 @@ extension ImageView {
                                     },
                                     completion: { finished in
                                         UIView.transitionWithView(sSelf, duration: transition.duration,
-                                            options: transition.animationOptions,
+                                            options: [transition.animationOptions, .AllowUserInteraction],
                                             animations: {
                                                 transition.animations?(sSelf, image)
                                             },

+ 2 - 2
Sources/Info.plist

@@ -15,11 +15,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 	<key>NSPrincipalClass</key>
 	<string></string>
 </dict>

+ 2 - 2
Tests/KingfisherTests-OSX/Info.plist

@@ -15,10 +15,10 @@
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 </dict>
 </plist>

+ 2 - 2
Tests/KingfisherTests-tvOS/Info.plist

@@ -15,10 +15,10 @@
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 </dict>
 </plist>

+ 14 - 0
Tests/KingfisherTests/ImageCacheTests.swift

@@ -199,6 +199,20 @@ class ImageCacheTests: XCTestCase {
         XCTAssertFalse(exists)
     }
 
+    func testCachedImageIsFetchedSyncronouslyFromTheMemoryCache() {
+        cache.storeImage(testImage, forKey: testKeys[0], toDisk: false) { () -> () in
+            // do nothing
+        }
+
+        var foundImage: Image?
+
+        cache.retrieveImageForKey(testKeys[0], options: [.BackgroundDecode]) { (image, type) -> () in
+            foundImage = image
+        }
+
+        XCTAssertEqual(testImage, foundImage, "should have found the image immediately")
+    }
+
     func testIsImageCachedForKey() {
         let expectation = self.expectationWithDescription("wait for caching image")
         

+ 2 - 2
Tests/KingfisherTests/Info.plist

@@ -15,10 +15,10 @@
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.3</string>
+	<string>2.0.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>536</string>
+	<string>543</string>
 </dict>
 </plist>