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