Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Implementing a Like Button in a TableView using Parse.com/Swift

Hi everyone,

I'm working on a social app and trying to implement the customary "like button" for posts by users. Each post is in its own custom tableViewCell (a PFTableViewCell). I'm trying to follow the Anypic tutorial in the parse.com documentation, but I'm getting stuck at a few parts. One part in particular is updating the like counter. Here is what happens (so far) when a user taps the like button:

// MARK: - Like button
     func like(sender:UIButton) {
        var senderButton = sender
//I tried to access the cell this way, but build fails: let cell = tableView.cellForRowAtIndexPath(senderButton.tag)
        var postLike:PFObject = (objects as NSArray).objectAtIndex(senderButton.tag) as PFObject
        //disable like button so user cannot duplicate request
        shouldEnableLikeButton(enable:false)
        setLikeStatus(liked:true)
        var liked = !senderButton.selected

        //get current number of likes on post
        if var likeCounter = postLike["likeCount"] as? Int {
            //let cell = tableView.cellForRowAtIndexPath(senderButton.tag)
            //update likeCount
            if liked {
                likeCounter = likeCounter + 1
                println(likeCounter)
                cell.label_likes.text = "\(likeCounter)" //build fails here because I'm unable to access the custom cell
            }else {
                likeCounter = likeCounter - 1
                println(likeCounter)
                cell.label_likes.text = "\(likeCounter)" //build fails here because I'm unable to access the custom cell
            }
        }

Has anybody else been able to implement a like button and wouldn't mind sharing their approach. It is greatly appreciated. I've been stuck for a while on this one. :-(

Lukes Ivi
Lukes Ivi
2,001 Points

Hey, do you mind sending the repository for this? I'm having a similar issue but I'm unable to replicate it through the code in this discussion.

4 Answers

Stone Preston
Stone Preston
42,016 Points

Aaron Watkins I think I solved your problem. you need to create an NSIndexPath from the row (which is stored in the button tag), since cellForRowAtIndexPath takes an index path. currently you are just passing it a row, which is an int:

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

that should make it work. let me know if it doesnt

Stone Preston - absolutely right. That was exactly it. My mistake was assuming that i could use indexPath and sender interchangeably since I was just looking to identify the cell by the row number. Thank you and Stephen Whitfield very much! really appreciate you guys.

Stone Preston
Stone Preston
42,016 Points

no problem. glad I could help

Stone Preston I am trying to use your approach for implementing a like/unlike button functionality in my social app and am experiencing an issue - I can better explain privately. Any way I can reach you to show you the problem?

Stone Preston
Stone Preston
42,016 Points

this button.tag trick is pretty common. the button.tag is going to be set in cellForRowAtIndex path. basically what you do is inside that method, you set the buttons tag to the indexPath.row variable, that way each button corresponds to a specific index path.

you also need to attach the button to a function that gets called when you press it

so make sure you have something like this in your cellForRow method:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
 // ...
cell.likeButton.tag = indexPath.row
cell.likeButton.addTarget(self, action: "like:", forControlEvents: UIControlEvents.TouchUpInside)

  // ...
}

Haven't looked at the problem you're having in particular, but one comment I can make off the bat is setting the instance of your cell to the current indexPath and not the sender's tag. A suggestion too is not to set you sender to a local variable, since you've already defined that the sender is of type UIButton in your method params.

Thanks a lot guys

Stone Preston - I'm able to pass the indexPath to this function via the bit of code you had above. I had that in my cellForRow method. Based on what Stephen Whitfield said, I'll definitely not assign my sender to a local variable...now that I think about it, that is unnecessary.

But here's the tricky thing I'm running into. Each custom cell has a like button and a label. The like button executes the function which SHOULD increment/decrement the value in the label (the like count). When I print to the console, I'm able to increment the like count for each cell, but I can't figure out how to update the label. If it were in the cellForRow method I would do something like:

cell.label_likes.text = "\(likeCounter)" //where likeCounter is the updated value of like counts after the like button is pressed.

But I can't access that label.

Stone Preston
Stone Preston
42,016 Points

ah I see. and when you say it fails when you try and use cellForRowAtIndexPath, what do you mean fails? does it crash?

Maybe you could create a separate method that updates the label when the button is pressed?

let likeButton = UIButton(frame: devSetFrame)
likeButton.addTarget(self, action: "syncUI:", forControlEvents: .TouchUpInside)

func syncUI(sender: UIButton) {
   //Update cell label here
}
Stone Preston
Stone Preston
42,016 Points

still the same problem. he needs access to the cell where the button is that was pressed. using cellForRowAtIndexPath is what he needs, but for some reason its not working

Ah! Ok. He needs to access the cell outside of the cellForRow method. I've done this before in the past by creating a property of type CustomCell. No idea if it's preferred, but it works. I instantiated the cell in the cellForRow method so that the current cell is available in other parts of my code. Maybe you could try that and see if it works.

Stone Preston - sorry I shouldn't have said "failed". It doesn't compile when I try to run it.
Stephen Whitfield - would you mind providing a sample of your recommendation? I'll give it a shot.

Thanks again, guys. really appreciate your help. I've been staring at this thing for a while.

Stone Preston
Stone Preston
42,016 Points

what build errors do you get when you try and run it with that method call in there