We are using Kingfisher to download images for our iOS app and I have encountered many crashes when trying to cancel a download task
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000020
Crashed: com.apple.main-thread
0 CFNetwork 0x18436b058 HTTPParser::HTTPParser(__CFAllocator const*, HTTPParserClient*, HTTPParser*) + 44
1 CFNetwork 0x18424b27c HTTPMessage::commonInitialization(unsigned char, HTTPMessage const*) + 212
2 CFNetwork 0x18424b27c HTTPMessage::commonInitialization(unsigned char, HTTPMessage const*) + 212
3 CFNetwork 0x18424b41c HTTPMessage::HTTPMessage(HTTPMessage const*) + 112
4 CFNetwork 0x18436c1dc HTTPRequestMessage::HTTPRequestMessage(HTTPRequestMessage const*) + 36
5 CFNetwork 0x18422a74c HTTPRequest::HTTPRequest(HTTPRequest const*) + 24
6 CFNetwork 0x18422ce8c URLRequest::initialize(URLRequest const*, unsigned char) + 656
7 CFNetwork 0x1841e2bd8 _createRequestCopy(__CFAllocator const*, _CFURLRequest const*, unsigned char) + 152
8 CFNetwork 0x184355de0 -[NSURLRequest mutableCopyWithZone:] + 44
9 libswiftFoundation.dylib 0x105a95a0c URLRequest.init(_bridged:) + 77948
10 libswiftFoundation.dylib 0x105a99344 static URLRequest._unconditionallyBridgeFromObjectiveC(_:) + 92596
11 Kingfisher 0x102fb5788 SessionDelegate.remove(_:) + 93 (SessionDelegate.swift:93)
12 Kingfisher 0x102fb566c closure #1 in SessionDelegate.add(_:url:callback:) + 1000 (<compiler-generated>:1000)
13 Kingfisher 0x102fb9eb0 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed SessionDelegate, @unowned Int, @in_guaranteed SessionDataTask.TaskCallback) -> () + 84 (<compiler-generated>:84)
14 Kingfisher 0x102f46734 specialized closure #1 in Delegate.delegate<A>(on:block:) + 96 (<compiler-generated>:96)
15 Kingfisher 0x102fb9f34 partial apply for specialized closure #1 in Delegate.delegate<A>(on:block:) + 28 (<compiler-generated>:28)
16 Kingfisher 0x102fb14d0 SessionDataTask.cancel(token:) + 356 (<compiler-generated>:356)
17 Kingfisher 0x102f6de18 DownloadTask.cancel() + 74 (ImageDownloader.swift:74)
18 MyApp 0x1011e55f4 UIImageView.cancel() + 4310799860 (<compiler-generated>:4310799860)
...
...
For example we call this method when reusing cells in a tableview, where we cancel requests for cells that are not longer visible. We have created an extension on UIImageView to define convenience methods like cancel()
- What could be the reason for this crash? The download task in our code is an optional, so even when the object is not there anymore, calling
image?.downloadTask.cancel()
should not create crashes, should not even trigger those methods.
In some cases, I have seem that the app crashes when the HTTP Request have been cancelled by the server, but is not the only time it happens.
Here is a Sample code of what we do:
func fetchImage(fromURL url: URL, completion: @escaping (UIImage?, NSError?) -> Void) -> MyAppDownloadTask {
let resource = ImageResource(downloadURL: url)
let options: KingfisherOptionsInfo = [.targetCache(cache), .downloader(downloader)]
let task = KingfisherManager.shared.retrieveImage(with: resource, options: options, progressBlock: nil) { result in
switch result {
case .success(let value):
completion(value.image, nil)
case .failure(let error):
completion(nil, error.toNSError())
}
}
return MyAppDownloadTask(task: task)
}
private class MyAppDownloadTask {
let task: DownloadTask? // KingFisher task
init(task: DownloadTask?) {
self.task = task
}
func cancel() {
task?.cancel()
}
}
We call the cancel method when reusing cells in our collection view:
override func prepareForReuse() {
super.prepareForReuse()
downloadTask.cancel()
}