Search code examples
swiftparse-platformpfquery

Swift Changing Button State Based on Parse Query


I have a "Add User" button that upon button click sets the "status" object to "Pending". When a user has this value, I want to update my button text to say "Pending". With my current solution, the text automatically changes every button to "Pending" despite my strict condition to change the buttons only if the query matches "Pending". What is wrong with my logic that is changing all of the buttons in my tableview?

Button State Logic:

var friendshipStatusQuery = PFQuery(className: "Follow")

        friendshipStatusQuery.whereKey("status", equalTo: "Pending")

        friendshipStatusQuery.findObjectsInBackgroundWithBlock {
            (objects: [AnyObject]!, error: NSError!) -> Void in
            if error == nil {

                cell.addUserButton.setTitle("Pending", forState: UIControlState.Normal)

            } else {
                NSLog("Error: %@ %@", error, error.userInfo!)
            }
        }

Full Code:

import UIKit

class SearchUsersRegistrationTableViewController: UITableViewController {

    var userArray : NSMutableArray = []

    override func viewDidLoad() {
        super.viewDidLoad()

        var user = PFUser.currentUser()

        loadParseData()




    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        return 1

    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return userArray.count

    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell: SearchUsersRegistrationTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell

        let row = indexPath.row

        var individualUser = userArray[row] as! PFUser
        var username = individualUser.username as String

        var profileImage = individualUser["profileImage"] as? PFFile

        if profileImage != nil {

        profileImage!.getDataInBackgroundWithBlock({
            (result, error) in

            cell.userImage.image = UIImage(data: result)

        })
        } else {
            cell.userImage.image = UIImage(named: "profileImagePlaceHolder")

        }

        cell.usernameLabel.text = username

        cell.addUserButton.tag = row

        cell.addUserButton.addTarget(self, action: "addUser:", forControlEvents: .TouchUpInside)


        var friendshipStatusQuery = PFQuery(className: "Follow")

        friendshipStatusQuery.whereKey("status", equalTo: "Pending")

        friendshipStatusQuery.findObjectsInBackgroundWithBlock {
            (objects: [AnyObject]!, error: NSError!) -> Void in
            if error == nil {

                cell.addUserButton.setTitle("Pending", forState: UIControlState.Normal)

            } else {
                NSLog("Error: %@ %@", error, error.userInfo!)
            }
        }


        return cell

    }

    func loadParseData() {

        var user = PFUser.currentUser()

        var query : PFQuery = PFUser.query()

        query.whereKey("username", notEqualTo: user.username)


        query.findObjectsInBackgroundWithBlock {
            (objects:[AnyObject]!, error:NSError!) -> Void in

            if error == nil {

                if let objects = objects {

                    println("\(objects.count) users are listed")

                    for object in objects {


                        self.userArray.addObject(object)



                    }
                    self.tableView.reloadData()
                }
            } else {
                println("There is an error")
            }
        }
    }






    @IBAction func addUser(sender: UIButton) {

        println("Button Triggered")

        let addUserButton : UIButton = sender as UIButton!

        let user : PFObject = self.userArray.objectAtIndex(addUserButton.tag) as! PFObject



        var follow = PFObject(className: "Follow")



        follow["following"] = self.userArray.objectAtIndex(sender.tag)
        follow["follower"] = PFUser.currentUser().username
        follow["status"] = "Pending"


        follow.saveInBackground()


    }

}

Solution

  • What's happening is that the query is asking for any object in the Follow table who's status attribute == "Pending". If one or more objects in that table satisfy that condition, then the "Pending" title will be applied to all of the cells' buttons.

    There are two things to fix in the code, then. First, refine the Follow query to be about the current row, probably having something to do with a pointer attribute in the follow object being equal to userArray[row].

    Second, referring to cell directly in the query's completion block will have unwanted effects if the user scrolls the table around while the query is running. That cell will end up being reused to represent a different row. My practice is to cache the result of the query someplace (like in the user array) and reload the row at indexPath.