简体   繁体   English

可重用tableview单元中的UIButton图像切换问题

[英]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. 我正在尝试在我的社交iOS应用程序中实现类似功能-使用Swift,Parse作为后端以及Storyboard-用户可以在其中喜欢(和不喜欢)类似于Instagram或Facebook iOS应用程序的帖子。

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). 唯一的问题似乎是,当用户滚动帖子的tableview提要时,该当前用户不喜欢的其他帖子正在显示填充的“喜欢”按钮图像(就好像它们是“被喜欢”,但不是)。

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. 根据我的研究,我了解到可能发生这种情况是因为tableview中的单元格是可重用的(通过tableView.dequeueReusableCellWithIdentifier 。)*这是有道理的,因为当用户打开应用程序时,只会加载可见的单元格。 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. 因此,我进行了更多研究,发现尝试解决此问题的一种方法是使用prepareForReuse()方法重置自定义单元格的likeButton IBOutlet的图像。 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. 然后,在重新使用单元格时,tableView:cellForRowAtIndexPath:中的表视图委托将重置所有内容,包括基于从like查询获得的结果具有某些逻辑的likeButton图像。 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. 更新:作为答案的建议之一,此处不需要prepareForResuse()。

// 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: 在发布提要viewcontroller文件的cellForRowAtIndexPath中:

        // 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: 在post feed viewcontroller文件的likeButtonTapped中:

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: 在您的情况下,无需使用prepareForReuse方法,可以通过以下操作替换cellForRowAtIndexPath的代码来实现:

// 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. 为了使上面的代码正常工作,还需要在完成“喜欢/喜欢”操作时相应地更新currUserLikeObjects ,并更新currUserLikeObjects tableview单元以反映屏幕上的修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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