Need help with understanding how to use prepareForReuse() in UIKit. The documentation says
you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state
but what about resetting individual property attributes such as isHidden?
Assuming my cell has 2 labels where should I reset:
My tableView(_:cellForRowAt:) delegate has conditional logic to hide/show labels per cell.
The reuse identifier tells the system that an object can be reused for a cell entering the screen for which you request the same identifier. Show activity on this post. Reuse identifiers are required by UITableViewCell in order to support the dequeueing of reusable cells by uniquely identifying cell types.
DequeueReusableCell(String) Returns a reusable table view cell that was created with the given ReuseIdentifier. DequeueReusableCell(NSString, NSIndexPath) Returns a reusable table view cell for the given reuseIdentifier , properly sized for the indexPath .
tldr: use prepareForReuse
to cancel out existing network calls that can can finish after downloading a different indexPath. For all other intents and purposes just use cellForRow(at:
. This slightly against Apple docs. But that's how most devs do stuff. It's inconvenient to have cell configuration logic at both places...
Apple docs say use it to reset attributes not related to content. However based on experience it might easier to do just do everything inside cellForRow
for content and not. The only time that it actually makes sense is to
Quoting from Apple's docs for prepareForReuse
:
For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state.
e.g. if a cell was selected, you just set it to unselected, if you changed the background color to something then you just reset it back to its default color.
The table view's delegate in
tableView(_:cellForRowAt:)
should always reset all content when reusing a cell.
This means if you were trying to set the profile images of your contact list you shouldn't attempt to nil
images in prepareforreuse
, you should correctly set your images in the cellForRowAt
and if you didn't find any image then you set its image to nil
or a default image. Basically the cellForRowAt
should govern both the expected/unexpected status.
So basically the following is not suggested:
override func prepareForReuse() {
super.prepareForReuse()
imageView?.image = nil
}
instead the following is recommended:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.imageView?.image = image ?? defaultImage // unexpected situation is also handled.
// We could also avoid coalescing the `nil` and just let it stay `nil`
cell.label = yourText
cell.numberOfLines = yourDesiredNumberOfLines
return cell
}
Additionally default non-content related items as below is recommended:
override func prepareForReuse() {
super.prepareForReuse()
isHidden = false
isSelected = false
isHighlighted = false
// Remove Subviews Or Layers That Were Added Just For This Cell
}
This way you can safely assume when running cellForRowAt
then each cell's layout is intact and you just have to worry about the content.
This is the Apple's suggested way. But to be honest, I still think it's easier to dump everything inside cellForRowAt
just like Matt said. Clean code is important, but this may not really help you achieve that. But as Connor said the only time it's necessary is, if you need to cancel an image that is loading. For more see here
ie do something like:
override func prepareForReuse() {
super.prepareForReuse()
imageView.cancelImageRequest() // this should send a message to your download handler and have it cancelled.
imageView.image = nil
}
Additionally in the special case of using RxSwift: See here or here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With