Search code examples
iosswiftuitableviewpropertiesprepareforreuse

Swift iOS -How to clean up a Cell's Class Properties and an ImageView's Image (also inside the cell)?


I use CollectionViewCells and a TableViewCells inside my app but for this example, I'm just going to list the TableViewCell info because they both use prepareForReuse.

Inside the cell I have:

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var thumbnailImageView: UIImageView!
@IBOutlet weak var backgroundViewForPlayerLayer: UIView!

var data: MyData?
var currentTime: CMTime? // used to keep track of the current play time when the app is sent to the background

var playerItem: AVPlayerItem?
var player: AVPlayer?
var playerLayer: AVPlayerLayer?

When I get the table data for my cell I feed the data to the cell in cellForRowAtIndexPath. I pass it to a data property inside the cell and I set the cell's thumbnail image and title outlet's in awakeFromNib(). I understand how cells are scrolled off the scene and then reused so I use prepareForReuse to clean the cell up.

Here Apple says:

For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state. The table view's delegate in tableView(_:cellForRowAt:) should always reset all content when reusing a cell.

When it's time to clean up the cell in prepareForReuse I've found out through trial and error the best way to clean up a label's text is to use label.text = "" instead of label.text = nil and apparently from the above Apple doesn't want prepareToReuse to be used for more than light clean up. However, I've read other posts on SO that it's best to clean up and remove the AVPlayerLayer by setting it to nil and removing it from its super layer in prepareForReuse.

I have 2 questions

  1. If not inside prepareForReuse then where do I reset the currentTime and data properties to nil and the imageView's image to nil? This is assuming the app was sent to the background and currentTime property was set to some value.
  2. If I cannot set a label's text to nil in prepareForReuse then why is it best to set the AVPlayerLayer to nil in prepareForReuse?

The TableVIewCell:

class MyCell: UITableViewCell{

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var thumbnailImageView: UIImageView!

var data: MyData?
var currentTime: CMTime?
var playerItem: AVPlayerItem?
var player: AVPlayer?
var playerLayer: AVPlayerLayer?

override func awakeFromNib() {
        super.awakeFromNib()

        NotificationCenter.default.addObserver(self, selector: #selector(appHasEnteredBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)

        titleLabel.text = data.title!
        thumbnailImageView.image = data.convertedUrlToImage() // url was converted to an image

        configureAVPlayer() //AVPlayer is configured
}


override func prepareForReuse() {
        super.prepareForReuse()

        titleLabel.text = ""

        player?.pause()
        playerLayer?.player = nil
        playerLayer?.removeFromSuperlayer()

        // should I reset these 3 here or somewhere else?
        data = nil
        currentTime = nil
        thumbnailImageView.image = nil
}

@objc func appHasEnteredBackground() {

        currentTime = player.currentTime()
        // pause the player...
}

}

cellForRowAtIndexPath:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

        let data = tableData[indexPath.row]

        cell.data = data

        return cell
}

Solution

  • 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.