Reputation: 578
I would like to implement a tableview with cells that display an image. The images will be loaded asynchroniously. For better scrolling I want the request to be canceled if the cell scrolls out of the view. My code so far works, but I don't know how to detect if the cell is visible or already "scrolled over".
Here's my code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("EventsTableCell", forIndexPath: indexPath) as! EventsTableCell
var elem : Event = data[indexPath.row] as Event
cell.headlineLabel.text = elem.getName()
cell.secondLabel.text = elem.getDescription()
cell.progressView.setProgress(0.0,animated: true)
if let image = ImageCache.getImage(elem.getId()) {
cell.coverImage.image = image
cell.progressView.removeFromSuperview()
} else {
cell.coverImage.image = UIImage(named: "loading")
if(elem.getCover() == nil){
//NOIMAGE
cell.progressView.removeFromSuperview()
}else{
println("start request for" + elem.getName()!)
cell.request = Alamofire.request(.GET, elem.getCover()!)
.progress {
(_, totalBytesRead, totalBytesExpectedToRead) in
dispatch_async(dispatch_get_main_queue()) {
// 6
cell.progressView.setProgress(Float(totalBytesRead) / Float(totalBytesExpectedToRead), animated: true)
// 7
if totalBytesRead == totalBytesExpectedToRead {
cell.progressView.removeFromSuperview()
}
}
}
.response { (request, response, data, error) in
if error == nil && cell.coverImage.image != nil {
ImageCache.addImage(elem.getId(),image: UIImage(data: data!, scale:1)!)
cell.coverImage.image = UIImage(data: data!, scale:1)
}else{
}
}
}
}
return cell
}
And with the following code I can cancel the request:
cell.request!.cancel()
I also noticed that the progressView isn't displayed sometimes, or maybe will be deleted from the superview to early, maybe someone can help.
Thanks Tobias
Upvotes: 2
Views: 472
Reputation: 534893
For better scrolling I want the request to be canceled if the cell scrolls out of the view.
Implement tableView:didEndDisplayingCell:forRowAtIndexPath:
and, in it, cancel the download for this row. That is exactly what this delegate method is for!
Upvotes: 3
Reputation: 17043
Cells are reused by table view for performance reasons. So the same cell could be used a lot of time for different indexPath.
Following line
tableView.dequeueReusableCellWithIdentifier("EventsTableCell", forIndexPath: indexPath) as! EventsTableCell
creates a new EventsTableCell object only if there is no one to be reused!
So now an progressView
issue is clear - you remove it from your cell by calling
cell.progressView.removeFromSuperview()
but you never add it. For example you could add it right after dequeueReusableCellWithIdentifier
call and remove later if needed. I also think in your case it will be better not to remove/add it but hide/show instead:
cell.progressView.hidden = false
Quite the same for an image request - you can call
cell.request?.cancel()
just after dequeueReusableCellWithIdentifier
To make your code more obvious you can cancel in prepareForReuse method of EventsTableCell but it will have the same effect.
prepareForReuse
Prepares a reusable cell for reuse by the table view's delegate.
Upvotes: 1