简体   繁体   中英

UIButton image toggling issue in reusable tableview cell

I'm trying to implement a like feature in my social networking iOS app - using Swift, Parse as the backend, and Storyboard - where users can like (and unlike) posts similar to the Instagram or Facebook iOS apps.

The only issue seems to be that when a user scrolls the tableview feed of posts, other posts that weren't liked by that current user are showing the filled like button image (as if they were Liked, but they were not).

Based on my research, I learned that this may be happening because the cells in the tableview are reusable (via tableView.dequeueReusableCellWithIdentifier .)*​ And this makes sense because when the user opens the app, only the visible cells are loaded. And when the user scrolls the tableview, the cells are recycled.

Therefore, I researched some more and found that one option to try and tackle this issue is to use the prepareForReuse() method to reset the likeButton IBOutlet's image of the custom cell. The table view's delegate in tableView:cellForRowAtIndexPath: then resets all content when reusing a cell, including the likeButton image with some logic based on the results obtained from the like query. It works initially, but unfortunately, this for some reason disrupts the behavior of the like button when the user tries to like a post.

UPDATE: prepareForResuse() is not required here as one of the answer's suggests.

// In custom cell file:

    override func prepareForReuse() {
        super.prepareForReuse()

        // Set likeButton image to the default unfilled version
        let image = UIImage(named: "likeButtonUnfilled")
        self.likeButton.setImage(image, forState: UIControlState.Normal)

    }

In the cellForRowAtIndexPath of the post feed viewcontroller file:

        // currUserLikeObjects is an array of PFObjects that contains the results returned from the like query (all of the objects that the current user has liked) 
        for object in currUserLikeObjects {

            if object["toPost"]?.objectId! == postObject.objectId {

                // Toggle likeButton image to filled version
                let image = UIImage(named: "likeButtonFilled") as UIImage!
                cell.likeButton.setImage(image, forState: UIControlState.Normal)

            }

        }

In likeButtonTapped of the post feed viewcontroller file:

func likeButtonTapped(sender: UIButton) {

    sender.enabled = false

    let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
    let cell = tableView.cellForRowAtIndexPath(indexPath) as! PostTableViewCell

    let likeObject = PFObject(className: ParseHelper.ParseLikeClass)
    var likedPost: PFObject = (self.objects![indexPath.row] as? PFObject)!

        if (cell.likeButton.currentImage!.isEqual(UIImage(named: "likeButtonUnfilled"))) {
            /* The post is NOT liked already by the currentUser (likeButton image is NOT filled)
            1. Save the like object to Parse
            2. If successfully saved, increment the likeCount and update it in Parse (Remember: Enable likeButton)
            3. If successfully saved, toggle the image to the filled version
            */

            // 1
            likeObject["fromUser"] = PFUser.currentUser()!
            likeObject["toPost"] = likedPost

            likeObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in

                if (error == nil) {
                    print("SUCCESS: Saved likeObject in database.")

                    // 2
                    likedPost.incrementKey(ParseHelper.ParsePostLikeCount, byAmount: 1)
                    likedPost.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in

                        if (error == nil) {
                            // The likeCount key has been incremented
                            print("SUCCESS: The likeCount key has been incremented. Toggling like button image to FILLED.")

                            // 3
                            var image = UIImage(named: Helper.likeButtonFilled)
                            cell.likeButton.setImage(image, forState: UIControlState.Normal)

                        } else {
                            // There was a problem, check error.description
                            print("FAIL: The likeCount key has NOT been incremented.")

                            // Delete the likeObject since the likeCount was not successfully saved
                            likeObject.deleteInBackgroundWithBlock( {(succeeded: Bool?, error: NSError?) -> Void in

                                if (error == nil) {
                                    print("SUCCESS: Deleted likeObject from Parse since likeCount key has not successfully been incremented.")

                                    self.showAlertMessage((error?.description)!)

                                } else {
                                    print("FAIL: Unable to delete the likeObject from Parse in response to likeCount key NOT incrementing.")

                                }

                            })

                        }

                    }

                    print("Enabling sender & reloading data.")
                    sender.enabled = true
                    self.tableView.reloadData()

                } else {
                    print("FAIL: Unable to save like object in Parse.")
                    self.showAlertMessage("Unable to like this post at this time.")

                }
            }

        } else if (cell.likeButton.currentImage!.isEqual(UIImage(named: "likeButtonFilled"))) {
            /* The post is liked already by the currentUser (likeButton image is filled)
            1. Delete the likeObject from Parse
            2. If successfully deleted, only if the likeCount is greater than 0 to avoid a negative likeCount, decrement the likeCount and update it in Parse (Remember: Enable likeButton)
            3. If successfully deleted, toggle the image to the unfilled version
            */

            // 1
            likeObject.deleteInBackgroundWithBlock( {(succeeded: Bool?, error: NSError?) -> Void in

                if (error == nil) {
                    print("SUCCESS: Deleted likeObject from Parse (unliked post).")

                    // 2
                    likedPost.incrementKey(ParseHelper.ParsePostLikeCount, byAmount: -1)

                    likedPost.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in

                        if (error == nil) {
                            // The likeCount key has been decremented
                            print("SUCCESS: The likeCount key has been decremented.")

                            // 3
                            var image = UIImage(named: Helper.likeButtonUnfilled)
                            cell.likeButton.setImage(image, forState: UIControlState.Normal)

                        } else {
                            print("FAIL: The likeCount key has NOT been decremented.")

                            // Delete the likeObject from the Like class since the likeCount was not successfully saved?

                        }

                    }

                    print("Enabling sender & reloading data.")
                    sender.enabled = true
                    self.tableView.reloadData()

                } else {

                    print("FAIL: Unable to delete the like object from Parse.")

                }

            })

        } 

} 

There is no require to use prepareForReuse method in your case, you can achieve by replacing your code in cellForRowAtIndexPath by following:

// Set likeButton image to the default unfilled version
var image = UIImage(named: "likeButtonUnfilled")

// currUserLikeObjects is an array of PFObjects that contains the results returned from the like query (all of the objects that the current user has liked) 
for object in currUserLikeObjects {
    if object["toPost"]?.objectId! == postObject.objectId {
         // Toggle likeButton image to filled version
         image = UIImage(named: "likeButtonFilled") as UIImage!
         break // Terminate loop when we found required object
    }
}
self.likeButton.setImage(image, forState: UIControlState.Normal)

For above code to work correctly it's also require that you are updating your currUserLikeObjects accordingly when Like/Unlike action is done and updating perticular tableview cell to reflect modification on screen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM