Common tasks related to the ImageDownloader in Kingfisher.
ImageDownloader wraps a URLSession for downloading an image from the Internet. Similar to ImageCache, there
is a ImageDownloader/default downloader for downloading tasks.
Usually, you may use Kingfisher's view extension methods or KingfisherManager to retrieve an image. They will try to search in the cache first to prevent unnecessary download task. In some cases, if you only want to download a target image without caching it:
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)
}
}
When you have permission control for your image resource, you can modify the request by using a .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)])
If you need to perform some asynchronous operation before modifying the request, create a type and conform 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)
}
}
}
Similar as above, you can use the .requestModifier to use this modifier. In this case, the setImage(with:options:) or ImageDownloader.downloadImage(with:options:) method will not return a DownloadTask anymore (since it does not start the download task immediately). Instead, you observe one from the onDownloadTaskStarted callback if you need a reference to the task:
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)])
If the downloading started, a DownloadTask will be returned. You can use it to cancel an on-going download task:
let task = downloader.downloadImage(with: url) { result in
// ...
case .failure(let error):
print(error.isTaskCancelled) // true
}
}
// After for a while, before download task finishes.
task?.cancel()
If the task already finished when you call task?.cancel(), nothing will happen.
Similar, the view extension methods also return DownloadTask. You can store and cancel it:
let task = imageView.kf.set(with: url)
task?.cancel()
Or, you can call cancelDownloadTask 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`.
NSURLCredentialThe ImageDownloader uses a default behavior (.performDefaultHandling) when receives a challenge from server. If you need to provide your own credentials, setup an 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)
}
}
By default, the download timeout for a request is 15 seconds. To set it for the downloader:
// Set timeout to 1 minute.
downloader.downloadTimeout = 60
To define a timeout for a certain request, use a .requestModifier:
let modifier = AnyModifier { request in
var r = request
r.timeoutInterval = 60
return r
}
downloader.downloadImage(with: url, options: [.requestModifier(modifier)])