In WWDC 2021 video, Protect mutable state with Swift actors, they provide the following code snippet:
actor ImageDownloader {
private var cache: [URL: Image] = [:]
func image(from url: URL) async throws -> Image? {
if let cached = cache[url] {
return cached
}
let image = try await downloadImage(from: url)
cache[url] = cache[url, default: image]
return cache[url]
}
func downloadImage(from url: URL) async throws -> Image { ... }
}
The issue is that actors offer reentrancy, so cache[url, default: image]
reference effectively ensures that even if you performed a duplicative request because of some race, that you at least check the actor’s cache after the continuation, ensuring that you get the same image for the duplicative request.
And in that video, they say:
A better solution would be to avoid redundant downloads entirely. We’ve put that solution in the code associated with this video.
But there is no code associated with that video on the website. So, what is the better solution?
I understand the benefits of actor reentrancy (as discussed in SE-0306). E.g., if downloading four images, one does not want to prohibit reentrancy, losing concurrency of downloads. We would, effectively, like to wait for the result of a duplicative prior request for a particular image if any, and if not, start a new downloadImage
.