Tom Lee
Tom Lee

Reputation: 95

UITableViewCell custom button image displaying incorrectly after UITableView scrolling

I have UITableViewCells that contains a custom button, which is an image. When the button is pressed, the image changes. However, when I scroll up and down the tableView, the cell that is tapped no longer displays the right image, or the "tapped" image is displaying elsewhere. I understand this problem is related to the cells being dequeued and reused. What I've tried to do is create a delegate in my custom cell class. The delegate calls a method in the tableViewController class. I am doing this with the code

self.delegate?.pressedButtonInCell?(self)

However this is not working..why?

=======custom cell class====

import UIKit
@objc protocol BoostCellDelegate{
optional func pressedButtonInCell(cell:BoostCell)
optional func displayAlert (title:String , error: String)
}
class BoostCell: UITableViewCell {
var delegate:BoostCellDelegate?
var boosted = false
var boostedButton = UIImage(named: "boostButtons.png")
@IBOutlet var userImage: UIImageView!
@IBOutlet var name: UILabel!

@IBOutlet var createdAt: UILabel!
@IBOutlet var boostButton: UIButton!
@IBAction func boostPressed(sender: UIButton) {

        let objectId = sender.titleLabel!.text!
        var query = PFQuery(className:"boostPost")
        query.getObjectInBackgroundWithId(objectId) {
            (boostPost: PFObject!, error: NSError!) -> Void in
            if error != nil {
                NSLog("%@", error)
                self.delegate?.displayAlert?("Something's gone wrong", error: "Might be the bad reception")
            } else {
                if boostPost != nil{
                    if boostPost["boostedBy"] != nil {
                        var boostedByArray : NSArray = boostPost["boostedBy"] as NSArray
                        if boostedByArray.containsObject(PFUser.currentUser().username){
                            println("username already boosted")

                        }
                        else{
                        var boostNumber = boostPost["boostNumber"] as Int
                        boostNumber++
                        boostPost["boostNumber"] = boostNumber
                        boostPost.addObject(PFUser.currentUser().username, forKey:"boostedBy")
                        boostPost.saveInBackground()
                        println("new username added to boosted")
                        self.delegate?.pressedButtonInCell?(self)
                        }
                    }
                    else if boostPost["boostedBy"] == nil{
                    var boostNumber = boostPost["boostNumber"] as Int
                    boostNumber++
                    boostPost["boostNumber"] = boostNumber
                    boostPost.addObject(PFUser.currentUser().username, forKey:"boostedBy")
                    boostPost.saveInBackground()
                    println("new username added to boosted")
                    self.delegate?.pressedButtonInCell?(self)

=====================================code in tableViewController class =========

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as BoostCell

    cell.name.text = userNewNames[indexPath.row]
    cell.content.text = userNewContent[indexPath.row]
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    cell.createdAt.text = userCreatedAt[indexPath.row]
    cell.delegate = self

    if userBoostedBy[indexPath.row].count == 2 {
        cell.boostedBy.text = "1 boost"
    }
    else if userBoostedBy[indexPath.row].count > 2 {
        var count = userBoostedBy[indexPath.row].count - 1
        cell.boostedBy.text = "\(count) boosts"
    }
    else {
        cell.boostedBy.text = "0 boost"
    }

    if (userButtonState[indexPath.row] == true) {
        cell.boostButton.setImage(self.boostedButton, forState: UIControlState.Normal)
    }
    else {
        cell.boostButton.setImage(self.unBoostedButton, forState: UIControlState.Normal)
    }

    userImagesFiles[indexPath.row].getDataInBackgroundWithBlock({ (imageData:NSData!, error:NSError!) in
        if error == nil {
            let image = UIImage(data: imageData)
            cell.userImage.image = image
        }
    })
    cell.boostButton.setTitle(objectIds[indexPath.row], forState: UIControlState.Normal)
    func pressedButtonInCell(cell:BoostCell)
    {
        cell.boostButton.setImage(self.boostedButton, forState: UIControlState.Normal)
    }
    // function to display the alert message
    func displayAlert (title:String , error: String){
        var alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: {
            action in

        }))
        self.presentViewController(alert, animated: true, completion: nil)
    }
    return cell
}

Upvotes: 3

Views: 922

Answers (1)

pbasdf
pbasdf

Reputation: 21536

It looks like your cellForRowAtIndexPath method uses userButtonState[indexPath.row] to determine whether to change the image for the boostButton. So, you just need to amend your pressedButtonInCell method to set userButtonState for the relevant row:

func pressedButtonInCell(cell:BoostCell)
{
    cell.boostButton.setImage(self.boostedButton, forState: UIControlState.Normal)
    if let indexPath = self.tableView.indexPathForCell(cell) {
        userButtonState[indexPath.row] = true
    }
}

(This assumes self.tableView points to your table view; if not amend to provide the correct reference). Now, when you press the button on a row, the relevant element of the array will be set to true. If the row then scrolls off screen, when it scrolls back on again, the tableView:cellForRowAtIndexPath: method will check userButtonState, find it to be true and so update the image for the button. Conversely, if userButtonState is false, the image is reset (just in case the re-used cell happened to have the boostedButton image).

Upvotes: 2

Related Questions