|
|
@@ -26,9 +26,13 @@
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
+/// Progress update block of downloader.
|
|
|
public typealias ImageDownloaderProgressBlock = DownloadProgressBlock
|
|
|
-public typealias ImageDownloaderCompletionHandler = CompletionHandler
|
|
|
|
|
|
+/// Completion block of downloader.
|
|
|
+public typealias ImageDownloaderCompletionHandler = ((image: UIImage?, error: NSError?, imageURL: NSURL?) -> ())
|
|
|
+
|
|
|
+/// Download task.
|
|
|
public typealias RetrieveImageDownloadTask = NSURLSessionDataTask
|
|
|
|
|
|
private let defaultDownloaderName = "default"
|
|
|
@@ -36,6 +40,24 @@ private let downloaderBarrierName = "com.onevcat.Kingfisher.ImageDownloader.Barr
|
|
|
private let imageProcessQueueName = "com.onevcat.Kingfisher.ImageDownloader.Process."
|
|
|
private let instance = ImageDownloader(name: defaultDownloaderName)
|
|
|
|
|
|
+/**
|
|
|
+* Protocol of `ImageDownloader`.
|
|
|
+*/
|
|
|
+@objc public protocol ImageDownloaderDelegate {
|
|
|
+ /**
|
|
|
+ Called when the `ImageDownloader` object successfully downloaded an image from specified URL.
|
|
|
+
|
|
|
+ :param: downloader The `ImageDownloader` object finishes the downloading.
|
|
|
+ :param: image Downloaded image.
|
|
|
+ :param: URL URL of the original request URL.
|
|
|
+ :param: response The response object of the downloading process.
|
|
|
+ */
|
|
|
+ optional func imageDownloader(downloader: ImageDownloader, didDownloadImage image: UIImage, forURL URL: NSURL, withResponse response: NSURLResponse)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+* `ImageDownloader` represents a downloading manager for requesting the image with a URL from server.
|
|
|
+*/
|
|
|
public class ImageDownloader: NSObject {
|
|
|
|
|
|
class ImageFetchLoad {
|
|
|
@@ -55,6 +77,9 @@ public class ImageDownloader: NSObject {
|
|
|
/// 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.
|
|
|
public var trustedHosts: Set<String>?
|
|
|
|
|
|
+ /// Delegate of this `ImageDownloader` object. See `ImageDownloaderDelegate` protocol for more.
|
|
|
+ public weak var delegate: ImageDownloaderDelegate?
|
|
|
+
|
|
|
// MARK: - Internal property
|
|
|
let barrierQueue: dispatch_queue_t
|
|
|
let processQueue: dispatch_queue_t
|
|
|
@@ -187,7 +212,9 @@ public extension ImageDownloader {
|
|
|
|
|
|
// MARK: - NSURLSessionTaskDelegate
|
|
|
extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
-
|
|
|
+ /**
|
|
|
+ This method is exposed since the compiler requests. Do not call it.
|
|
|
+ */
|
|
|
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
|
|
|
|
|
|
if let URL = dataTask.originalRequest.URL, callbackPairs = fetchLoads[URL]?.callbacks {
|
|
|
@@ -198,6 +225,9 @@ extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
completionHandler(NSURLSessionResponseDisposition.Allow)
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ This method is exposed since the compiler requests. Do not call it.
|
|
|
+ */
|
|
|
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
|
|
|
|
|
|
if let URL = dataTask.originalRequest.URL, fetchLoad = fetchLoads[URL] {
|
|
|
@@ -216,6 +246,9 @@ extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ This method is exposed since the compiler requests. Do not call it.
|
|
|
+ */
|
|
|
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
|
|
|
|
|
|
if let URL = task.originalRequest.URL {
|
|
|
@@ -228,6 +261,9 @@ extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
|
|
|
if let fetchLoad = self.fetchLoads[URL] {
|
|
|
if let image = UIImage(data: fetchLoad.responseData) {
|
|
|
+
|
|
|
+ self.delegate?.imageDownloader?(self, didDownloadImage: image, forURL: URL, withResponse: task.response!)
|
|
|
+
|
|
|
if fetchLoad.shouldDecode {
|
|
|
self.callbackWithImage(image.kf_decodedImage(), error: nil, imageURL: URL)
|
|
|
} else {
|
|
|
@@ -235,6 +271,13 @@ extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
+ // If server response is 304 (Not Modified), inform the callback handler with NotModified error.
|
|
|
+ // It should be handled to get an image from cache, which is response of a manager object.
|
|
|
+ if let res = task.response as? NSHTTPURLResponse where res.statusCode == 304 {
|
|
|
+ self.callbackWithImage(nil, error: NSError(domain: KingfisherErrorDomain, code: KingfisherError.NotModified.rawValue, userInfo: nil), imageURL: URL)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
self.callbackWithImage(nil, error: NSError(domain: KingfisherErrorDomain, code: KingfisherError.BadData.rawValue, userInfo: nil), imageURL: URL)
|
|
|
}
|
|
|
} else {
|
|
|
@@ -247,6 +290,9 @@ extension ImageDownloader: NSURLSessionDataDelegate {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ This method is exposed since the compiler requests. Do not call it.
|
|
|
+ */
|
|
|
public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
|
|
|
|
|
|
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
|