I enabled Strict Swift Concurrency Check and get some warnings. I would love to discuss and understand them. This is my code.
class DownloadImageAsyncImageLoader {
let url = URL(string: "https://picsum.photos/200")!
func handleResponse(data: Data?, response: URLResponse?) -> UIImage? {
guard let data = data,
let image = UIImage(data: data),
let response = response as? HTTPURLResponse,
response.statusCode >= 200 && response.statusCode < 300 else {
return nil
}
return image
}
func downloadWithEscaping(completion: @escaping (UIImage?, Error?) -> Void) {
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard let image = self?.handleResponse(data: data, response: response) else {
completion(nil, error)
return
}
completion(image, nil)
}
.resume()
}
}
I got two warnings inside URLSession data task callback.
- Capture of 'self' with non-sendable type 'DownloadImageAsyncImageLoader?' in a
@Sendable
closure.
This class has no data at all. I can make it final and conform to Sendable explicitly. Then this warning goes away. If this class cannot be final, what should we do?
- Capture of 'completion' with non-sendable type '(UIImage?, (any Error)?) -> Void' in a
@Sendable
closure
I have no idea how to address this one.
I strongly suggest that you write this using Swift Concurrency, instead of using completion handlers. It would look something like this:
As for the second error, it is saying that your completion handler is not
@Sendable
. You can fix the error by just marking it as@Sendable
,but of course this puts certain restrictions on what you can do in the completion handler (the same restrictions as what you can do in the completion handler of
URLSession.shared.dataTask(with: url)
), so you might get more errors depending on how you use this method.For the first error, if your class cannot be
final
, that means subclasses can add whatever properties they like in a non-sendable way, so capturingself
is inherently unsafe.That said,
handleResponse
doesn't use any instance properties. It might as well be astatic func
(orclass func
if you allow subclasses to override it). Then you can call it withSelf.handleResponse(...)
instead ofself.handleResponse(...)
.