Hi,
I really enjoyed both sessions as they helped me improve loading images in a collection view. I am currently experimenting with both codes and I'd like to combine them.
As far as I understand from the "Make blazing fast lists and collection views" session there are key considerations:
- In the cell registration get the current asset for your model
- If it is a placeholder, download the asset and afterwards reconfigure the cell. This is due to cells potentially being reused already.
- If it is not a placeholder, we can just assign it to the cell's image view
From the other talk about "protecting mutable state with Swift actors", I found out about protecting the image cache by using actors and that one should be aware of changed state after re-entry from an await.
Now I am trying to combine the two talks, which is a bit difficult if I want to make sure that I use it correctly, so here are my ideas:
- I want an ImageLoader actor, that protects its cache state
- By using an actor, both reading from the cache and storing the cache become async operations (since if the cache is currently used, we need to "await" our turn to read from it)
- By doing this, in our cell registration, we can no longer fetch the asset synchronously and check if it is a placeholder or not.
- This means that even if we already have a cached image, the re-entry might be later and the cell might already be reused and therefore we can't just set the imageView image.
- Moreover we cannot call reconfigure of the cell registration (via the data source snapshot) anymore, since this would put us in an infinite loop.
Additionally, preparing the image before displaying it also is an async operation. And since those images are larger in memory, I'd want to avoid caching images - I'd rather prepare them in the cell registration handler, which would make it async as well.
Here is my code:
cell.artworkView.image = UIImage(named: "DefaultArtwork")
async {
let asset: AlbumAsset = await self.assetStore.asset(forURL: artworkURL)
switch asset {
case .placeholder:
await self.assetStore.downloadAsset(forURL: artworkURL)
self.reconfigureAlbum(albumID)
case .image(let image):
let thumbnailImage = await image.byPreparingThumbnail(ofSize: .init(width: 100, height: 100))
DispatchQueue.main.async {
cell.artworkView.image = thumbnailImage // Problem
}
}
}
Any help is appreciated as to how I can improve the situation so I can use actors, while still following the rules for updating a cell.
I'd need something like a synchronous way of getting images, while having an asynchronous way of downloading and preparing images, and maintaining mutable state (cache).
Thanks for any help.