i have a tableview with a custom cell which includes a label and image, on load its fine and all cells are displayed correctly.
However when i scroll down as there are over 200 cells, when i scroll back up, the cells data in the cells change - so for example - i could have the correct image but wrong label or wrong image but correct label. I am not sure what i am doing wrong.
Here is my code so far:
import UIKit
class SearchTableViewCell: UITableViewCell {
static let identifier = "SearchTableViewCell"
@IBOutlet var loader: UIActivityIndicatorView!
@IBOutlet var nameLabel: UILabel!
@IBOutlet var addressLabel: UILabel!
@IBOutlet var locationImageView: UIImageView!
var currentIndexPath: IndexPath?
override func awakeFromNib() {
super.awakeFromNib()
nameLabel.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 25)
nameLabel.textColor = .white
nameLabel.numberOfLines = 1
addressLabel.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 15)
addressLabel.textColor = .white
addressLabel.numberOfLines = 0
locationImageView.clipsToBounds = true
locationImageView.layer.cornerRadius = 8.0
locationImageView.contentMode = .scaleAspectFill
}
func configure(with urlString: String, name: String, address: String, station: String) {
loader.startAnimating()
loader.isHidden = false
guard let url = URL(string: urlString) else {
return
}
let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else {
return
}
let locationImage = UIImage(data: data)
DispatchQueue.main.async {
self?.nameLabel.text = name
self?.addressLabel.text = address
self?.locationImageView.image = locationImage
self?.loader.stopAnimating()
self?.loader.isHidden = true
}
}
task.resume()
}
static func nib() -> UINib {
return UINib(nibName: "SearchTableViewCell", bundle: nil)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
nameLabel.text = nil
locationImageView.image = nil
currentIndexPath = nil
}
}
CodePudding user response:
You are loading the contents of the cell asynchronously. The UITableView
will reuse the cells. So suppose:
- You are asked to create a cell. You begin to load the cell content asynchronously.
- Before the content can load, the user scrolls the cell off the screen. The system takes the cell and puts it in the reuse queue. (the load from step 1 is still going on)
- The system pulls the cell off the reuse queue, calls the reuse callback (zeroing out the content) and puts it back into the table view. (the load from step 1 is still going on)
- The asynchronous load from Step 1 finally completes and sets the values in the cell to its content.
Now the cell you had in Step 1 is the same as the new cell that was just put somewhere else in the table, but it has the wrong content because your asynchronous load finished after the cell was reused.
The cell is just for displaying information... it shouldn't be loading data. The Data Source is the guy that loads data. You need to rethink your design and change the place where you load data.
CodePudding user response:
here is a video that I used as an solution - https://www.youtube.com/watch?v=XFvs6eraBXM - hope this helps someone who needs it!