2
0

CommonTasks_Downloader.md 5.5 KB

Common Tasks - Downloader

Common tasks related to the ImageDownloader in Kingfisher.

Overview

ImageDownloader wraps a URLSession for downloading an image from the Internet. Similar to ImageCache, there is a ImageDownloader/default downloader for downloading tasks.

Download an image manually

Typically, you might use Kingfisher's view extension methods or KingfisherManager for image retrieval. These methods prioritize searching the cache to avoid unnecessary downloads. If you need to download an image without caching it, consider the following approach:

let downloader = ImageDownloader.default
downloader.downloadImage(with: url) { result in
    switch result {
    case .success(let value):
        print(value.image)
    case .failure(let error):
        print(error)
    }
}

Modify a request before sending

When managing access to your image resources with permission controls, you can customize the request using a KingfisherOptionsInfoItem/requestModifier(_:):

let modifier = AnyModifier { request in
    var r = request
    r.setValue("abc", forHTTPHeaderField: "Access-Token")
    return r
}
downloader.downloadImage(with: url, options: [.requestModifier(modifier)]) { 
    result in
    // ...
}

// This option also works for view extension methods.
imageView.kf.setImage(with: url, options: [.requestModifier(modifier)])

Use async request modifier

If an asynchronous operation is required before modifying the request, create a type that conforms to AsyncImageDownloadRequestModifier:

class AsyncModifier: AsyncImageDownloadRequestModifier {
    var onDownloadTaskStarted: ((DownloadTask?) -> Void)?

    func modified(for request: URLRequest, reportModified: @escaping (URLRequest?) -> Void) {
        var r = request
        someAsyncOperation { result in
            r.someProperty = result.property
            reportModified(r)
        }
    }
}

Similarly, use the KingfisherOptionsInfoItem/requestModifier(_:) to apply this modifier. In such scenarios, the KingfisherWrapper/setImage(with:placeholder:options:progressBlock:completionHandler:)-8lmr3 or ImageDownloader/downloadImage(with:options:completionHandler:)-2ztyq method will no longer return a DownloadTask directly, as the download task isn't initiated instantly. To reference the task, monitor the AsyncImageDownloadRequestModifier/onDownloadTaskStarted callback.

let modifier = AsyncModifier()
modifier.onDownloadTaskStarted = { task in
    if let task = task {
        print("A download task started: \(task)")
    }
}
let nilTask = imageView.kf.setImage(with: url, options: [.requestModifier(modifier)])

Cancel a download task

Once the download has started, a DownloadTask will be created and returned. This can be used to cancel an ongoing download task.

let task = downloader.downloadImage(with: url) { result in
    // ...
    case .failure(let error):
        print(error.isTaskCancelled) // true
    }

}

// After some time, but before the download task completes.
task?.cancel()

If you call DownloadTask/cancel() after the task has already finished, no action will be taken.

Likewise, the view extension methods return a DownloadTask as well. This allows you to store the task and cancel it if needed:

let task = imageView.kf.set(with: url)
task?.cancel()

Alternatively, you can invoke KingfisherWrapper/cancelDownloadTask()-2gg15 on the image view to cancel the current downloading task.

let task1 = imageView.kf.set(with: url1)
let task2 = imageView.kf.set(with: url2)

imageView.kf.cancelDownloadTask()
// `task2` will be cancelled, but `task1` is still running. 
// However, the downloaded image for `task1` will not be set because the image view expects a result from `url2`.

Authentication with NSURLCredential

The ImageDownloader defaults to .performDefaultHandling upon receiving a server challenge. To supply custom credentials, configure an ImageDownloader/authenticationChallengeResponder:

// In ViewController
ImageDownloader.default.authenticationChallengeResponder = self

extension ViewController: AuthenticationChallengeResponsable {

    var disposition: URLSession.AuthChallengeDisposition { /* */ }
    let credential: URLCredential? { /* */ }

    func downloader(
        _ downloader: ImageDownloader,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
    {
        // Provide your `AuthChallengeDisposition` and `URLCredential`
        completionHandler(disposition, credential)
    }

    func downloader(
        _ downloader: ImageDownloader,
        task: URLSessionTask,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
    {
        // Provide your `AuthChallengeDisposition` and `URLCredential`
        completionHandler(disposition, credential)
    }
}

Set customize timeout

The default download timeout for a request is 15 seconds. To customize this for the downloader:

// Set the timeout to 1 minute.
downloader.downloadTimeout = 60

For setting a timeout specific to a request, utilize a KingfisherOptionsInfoItem/requestModifier(_:):

let modifier = AnyModifier { request in
    var r = request
    r.timeoutInterval = 60
    return r
}
downloader.downloadImage(with: url, options: [.requestModifier(modifier)])