What is the correct way to use prepareForReuse?
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
When calling prepareForReuse() in CustomTableViewCell.swift, UITableViewCells become unresponsive after several deletions from UITableView (Swift 3)
A few things. For performance reasons, you should only use prepareForReuse
to reset attributes that are related to the appearance of the cell and not content (like images and text). Set content like text and images in cellForRowAtIndexPath
delegate of your tableView and reset cell appearance attributes like alpha, editing, and selection state in prepareForReuse
. I am not sure why it continues to behave badly when you comment out that line and leave prepareForReuse
empty because so long as you are using a custom table view cell an empty prepareForReuse
should not affect performance. I can only assume it has something to do with you not invoking the superclass implementation of prepareForReuse
, which is required by Apple according to the docs:
override func prepareForReuse() {
// CELLS STILL FREEZE EVEN WHEN THE FOLLOWING LINE IS COMMENTED OUT?!?!
super.prepareForReuse()
}
The prepareForReuse
method is only ever intended to do minor cleanup for your custom cell.
Why we use super.prepareForReuse when using prepareForReuse of Custom cell in Swift
Simple answer: because Apple says so. The documentation says:
If you override this method, you must be sure to invoke the superclass implementation
That means call super
. Just do it. Clearly the UITableViewCell class itself does something in its implementation of prepareForReuse
, and Apple is telling you to make sure it gets to do that.
That's all there is to say about the matter, because Cocoa is closed source. You cannot see what UITableViewCell does. And you shouldn't care. Just do what Apple tells you. That is how to use the Cocoa framework.
custom UITableViewCells and proper use of prepareForReuse and removeFromSuperview
You shouldn't be removing the views, because then you incur the cost of recreating them. Instead you should just be setting the text to nil, but even then if every cell always has text you don't need to do that because the new text will replace the old before the cell is visible. Most use cases don't require you to use prepareForReuse
.
The duplication suggests that you are adding new views all the time and not updating your variables so each time you try to remove them nothing actually happens.
Reusable Cell isn't calling prepareForReuse function
You should subclass UITableView cell and inside your custom class override:
import UIKit
class CustomTableViewCell: UITableViewCell {
override func prepareForReuse() {
// your cleanup code
}
}
then in UITableViewDataSource method reuse the custom cell:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! CustomTableViewCell
return cell
}
Swift iOS -How to clean up a Cell's Class Properties and an ImageView's Image (also inside the cell)?
I found the answer here: prepareForReuse clean up
Seems the best way to clean up the cell is to do it in cellForRowAtIndexPath before setting the content.
Related Topics
iOS 7 Uiimagepicker Preview Black Screen
Application:Didreceiveremotenotification:Fetchcompletionhandler Not Called
Enable or Disable iPhone Push Notifications Inside the App
How to Asynchronously Load an Image in an Uiimageview
Return from Initializer Without Initializing All Stored Properties
Wrong Frame Size in Viewdidload
"Cannot Connect to Itunes Store" In-App Purchases
How to Detect If iOS App Is Running in UI Testing Mode
Uicollectionview Update a Single Cell
How to Both Stroke and Fill with Nsattributedstring W/ Uilabel
What Is the Correct Way to Use Prepareforreuse
Rotate a Uiview Around Its Center But Several Times
iPhone Image Captured from Camera Rotate -90 Degree Automatically
Uikeyboardframebeginuserinfokey & Uikeyboardframeenduserinfokey
Https iOS with Self Signed Certificate