可重复使用的表格视图单元格中的 UIButton 图像切换问题

Posted

技术标签:

【中文标题】可重复使用的表格视图单元格中的 UIButton 图像切换问题【英文标题】:UIButton image toggling issue in reusable tableview cell 【发布时间】:2016-02-24 18:41:31 【问题描述】:

我正在尝试在我的社交网络 ios 应用程序中实现一个点赞功能 - 使用 Swift、Parse 作为后端和 Storyboard - 用户可以在其中喜欢(和不喜欢)类似于 Instagram 或 Facebook iOS 应用程序的帖子。

唯一的问题似乎是,当用户滚动帖子的 tableview 提要时,当前用户不喜欢的其他帖子显示填充的喜欢按钮图像(好像他们被喜欢,但他们不是) .

根据我的研究,我了解到这可能是因为 tableview 中的单元格是可重复使用的(通过 tableView.dequeueReusableCellWithIdentifier.)*​ 这是有道理的,因为当用户打开应用程序时,只有可见的单元格被加载.并且当用户滚动 tableview 时,单元格会被回收。

因此,我进行了更多研究,发现尝试解决此问题的一种方法是使用prepareForReuse() 方法重置自定义单元格的likeButton IBOutlet 图像。 tableView:cellForRowAtIndexPath: 中的 table view 的委托然后在重用单元格时重置所有内容,包括 likeButton 图像以及基于从 like 查询获得的结果的一些逻辑。它最初可以工作,但不幸的是,当用户尝试点赞帖子时,由于某种原因,这会破坏点赞按钮的行为。

更新:这里不需要 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)

    

在 post feed 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)

            

        

likeButtonTappedpost feed viewcontroller 文件中:

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.")

                

            )

         

 

【问题讨论】:

【参考方案1】:

在您的情况下不需要使用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)

要使上述代码正常工作,还需要您在完成 Like/Unlike 操作时相应地更新 currUserLikeObjects 并更新特定的 tableview 单元格以反映屏幕上的修改。

【讨论】:

谢谢。我尝试了您的代码并对其进行了测试:我喜欢一个帖子,点赞按钮图像切换到填充版本。 当我拉动刷新或向下滚动然后返回到点赞的帖子时,点赞帖子的点赞按钮图像会切换回未填充的版本。 但如果我退出应用然后再次打开它,点赞按钮我喜欢的帖子的图像已正确设置为填充版本。注意:在 currUserLikeObjects 中存储like 对象的likeQuery 在viewDidLoad 中调用。 @dnadri 正如我在回答中解释的那样,当您对任何帖子进行服务器查询并获得成功时,您还需要更新您的 currUserLikeObjects (通过使用 objectId 向其中添加新对象,您会得到作为响应),对于不同(通过删除与 objectId 匹配的对象形式数组)相同 是的,我在likeButtonTapped func 中有代码,当用户点击like 按钮时在 Parse 中添加一个新的like 对象,并在用户不喜欢时删除该新的like 对象,这反过来应该更新currUserLikeObjects. 我更新了我的问题以显示我的 likeButtonTapped func 代码,该代码在用户喜欢/不喜欢时添加/删除对象,正如你所说。为了使这项工作正常工作,我还缺少什么?

以上是关于可重复使用的表格视图单元格中的 UIButton 图像切换问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 cellforrowatindexpath 之后更新自定义表格单元格中的 UIButton 图像?

如何使表格视图单元格中的按钮工作[重复]

自定义表格视图单元格中的可编辑文本字段

iOS:表格单元格中的 UILabel 和 UIButton

使 UIButton 保持在表格视图 rss 提要单元格的顶部 [重复]

如何在 ios 中使用图案图像在可扩展的 tableViewCell 中设置 UIButton