It's very clear from the session video how we can leverage cell configurations for information that is available synchronously, like titles for rows and locally-available images.
Are there recommendations for how to configure cells for asynchronously-loaded stuff, for example fetching a user's profile picture from the internet?
In the old style, we could subclass UITableViewCell and add an imageURL property, and then start loading the image immediately, with the ability to cancel the network request when prepareForReuse was called.
I can imagine some ways to put this logic into the data source, but I think we'd have to do index-path accounting (or something) to keep track of which network request belongs to which cell, in order to deal with updating the cell's configuration on successful completion, as well as cancelling if the cell is going to be reused before loading completes.
Are there better ways to approach this? Thanks!
Are there recommendations for how to configure cells for asynchronously-loaded stuff, for example fetching a user's profile picture from the internet?
In the old style, we could subclass UITableViewCell and add an imageURL property, and then start loading the image immediately, with the ability to cancel the network request when prepareForReuse was called.
I can imagine some ways to put this logic into the data source, but I think we'd have to do index-path accounting (or something) to keep track of which network request belongs to which cell, in order to deal with updating the cell's configuration on successful completion, as well as cancelling if the cell is going to be reused before loading completes.
Are there better ways to approach this? Thanks!
Cell configurations are flexible, and can be used in a number of different ways. They can be applied from outside the cell (e.g. directly from the code where you dequeue and return the cell to the table or collection view), which is great for simple cells where you don't need a custom cell subclass.
But you can also apply configurations to the cell from inside your own cell subclass. As a best practice, you should choose a single place to update and apply your configurations to the cell, and just re-run that code anytime you need to, instead of having multiple places in your code all trying to set or update the cell's configurations. In your cell subclass, the best place to do this is in an override of updateConfiguration(using state:), and you can request an update anytime you want by calling setNeedsUpdateConfiguration().
With that in mind, here's how you can use configurations with asynchronous content. First of all, you can keep the same image-loading code that you are familiar with. When the image loads, we'll set it to a loadedImage property on the cell. Anytime this property is set, we'll just ask for a configuration update for the cell. And finally, we override updateConfiguration(using state:) to set up the content configuration and apply it to the cell, based on the loaded image.
The first time the cell displays, loadedImage will likely be nil, but as soon as it loads, it triggers a configuration update where a new configuration is applied to the cell with that image.
If there are other asynchronous properties, or any other inputs that affect the cell's configuration, you can follow the exact same pattern.
But you can also apply configurations to the cell from inside your own cell subclass. As a best practice, you should choose a single place to update and apply your configurations to the cell, and just re-run that code anytime you need to, instead of having multiple places in your code all trying to set or update the cell's configurations. In your cell subclass, the best place to do this is in an override of updateConfiguration(using state:), and you can request an update anytime you want by calling setNeedsUpdateConfiguration().
With that in mind, here's how you can use configurations with asynchronous content. First of all, you can keep the same image-loading code that you are familiar with. When the image loads, we'll set it to a loadedImage property on the cell. Anytime this property is set, we'll just ask for a configuration update for the cell. And finally, we override updateConfiguration(using state:) to set up the content configuration and apply it to the cell, based on the loaded image.
Code Block swift var loadedImage: UIImage? { didSet { setNeedsUpdateConfiguration() } } override func updateConfiguration(using state: UICellConfigurationState) { var content = self.defaultContentConfiguration().updated(for: state) // You could also set a placeholder image here if desired, when loadedImage is nil content.image = self.loadedImage // You'll likely want to set a reserved layout size for the image, so it doesn't change the layout when it loads content.imageProperties.reservedLayoutSize = ... self.contentConfiguration = content }
The first time the cell displays, loadedImage will likely be nil, but as soon as it loads, it triggers a configuration update where a new configuration is applied to the cell with that image.
If there are other asynchronous properties, or any other inputs that affect the cell's configuration, you can follow the exact same pattern.