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
- If not inside
prepareForReuse
then where do I reset thecurrentTime
anddata
properties tonil
and theimageView's image
tonil
? This is assuming the app was sent to the background andcurrentTime
property was set to some value. - If I cannot set a label's text to nil in
prepareForReuse
then why is it best to set the AVPlayerLayer to nil inprepareForReuse
?
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
}