Search code examples
swiftparse-platformtableview

Tutorial in retrieving, mutating and saving array from Parse.com in Swift with UITableView


import UIKit

class FeedTableViewController: UITableViewController {
var navBar:UINavigationBar=UINavigationBar()
let font = UIFont(name: "Baskerville", size: 15)

var feedData:NSMutableArray = NSMutableArray()



required init(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
}




@IBAction func likeButton(sender: AnyObject) {
    if var votes:Int? = quote!.objectForKey("votes") as? Int {
        votes!++
    }

}

@IBAction func loadData(sender: AnyObject?) {
    feedData.removeAllObjects()

    var findFeedData:PFQuery = PFQuery(className: "userQuotes")

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

        if error == nil{
            if let objs = objects{
                for object in objs{
                    let quote:PFObject = object as! PFObject
                    self.feedData.addObject(quote)
                   // let user:PFUser = (object as! NSArray).lastObject as! PFUser



                }
                //println(self.feedData)

                let array:NSArray = self.feedData.reverseObjectEnumerator().allObjects
                self.feedData = NSMutableArray(array: array)

                NSOperationQueue.mainQueue().addOperationWithBlock({
                    self.tableView.reloadData()
                })
            }
        }

    }

}



override func viewDidAppear(animated: Bool) {

    self.loadData( nil )


}


override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Quotezilla"

    // 3
    //self.navigationItem.setRightBarButtonItem(rightSearchBarButtonItem, animated: true)

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

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

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete method implementation.
    // Return the number of rows in the section.
    return feedData.count
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell:QuoteTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! QuoteTableViewCell

     let quote:PFObject = self.feedData.objectAtIndex(indexPath.row) as! PFObject

    cell.contentTextView!.font = font
    cell.timeStampLabel!.font = font
    cell.publisherLabel!.font = font

    cell.contentTextView.alpha = 0
    cell.timeStampLabel.alpha = 0
    cell.publisherLabel.alpha = 0

    cell.contentTextView.text = quote.objectForKey("content") as! String
    //cell.publisherLabel.text = quote.objectForKey("publisher") as? String

  /*  func loadLikes(){
        if var votes:Int? = quote.objectForKey("votes") as? Int {
            votes!++
        }
    }*/



    var dateFormatter:NSDateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "EEEE, MMM d, h:mm a"
    cell.timeStampLabel.text = dateFormatter.stringFromDate(quote.createdAt!)

    var votes:Int? = quote["votes"] as? Int
    if votes == nil {
        votes = 0
    }


    cell.likesLabel?.text = "\(votes!)"


    var myObject = quote["publisher"] as? PFObject
    myObject?.fetchIfNeeded()

    if let foundUser = myObject as? PFUser{
        cell.publisherLabel.text = foundUser.username
        UIView.animateWithDuration(0.7, animations: {

            cell.contentTextView.alpha = 1
            cell.timeStampLabel.alpha = 1
            cell.publisherLabel.alpha = 1

        })
    }

        return cell
}

So what I am essentially attempting to do is create a likes or votes button. As you see in the code I have a likeButton action that is supposed to auto-increment the likes section in parse. I display the current likes that I have filled into the rows in Parse itself in the cellForRowAtIndexPath function. The problem is that I cannot call quote.objectForKey("votes"), because I initialize it later. I have been poring over this problem and cannot find a way to make the votes update in parse through the likeButton action.


Solution

  • You must live with life on the network. That means your table won't have certain data available when the App starts. Handle a missing object or missing key within a particular cell gracefully and just use some kind of placeholder value. When the parse callback executes, you are already correctly forcing a refresh.

    OK So BIG EDIT

    This class needed a lot of work. I'm not even going to spell out every change here, but it's basically a complete Parse.com tutorial at this point.

    This code compiles cleanly but I can't be sure of everything in your context. In particular do you have a 'likesButton' on every table row as part of your custom table cell view? I'm assuming that.

    class FeedTableViewController: UITableViewController {
        var navBar = UINavigationBar()
        let font = UIFont(name: "Baskerville", size: 15)
        var feedData = [PFObject]()
        static let cellID = "cell"
    
        // NOTE! See how this tag is set below
        @IBAction func likeButton(sender: UIButton) {
            let quote = feedData[sender.tag]
            if let votes = quote.objectForKey("votes") as? Int {
                quote.setObject(votes + 1, forKey: "votes")
            }
            else {
                // CHALLENGE FOR YOU: handle the case of no votes attribute
            }
            // UPDATE the local UI
            tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: sender.tag, inSection: 0)],
                    withRowAnimation: .None)
            // CHALLENGE FOR YOU: UPDATE Parse...start a new question if necessary
        }
    
        @IBAction func loadData(sender: AnyObject?) {
            feedData.removeAll()
            PFQuery(className: "userQuotes").findObjectsInBackgroundWithBlock {
                [unowned self]
                (objects: [AnyObject]?, error: NSError?) -> Void in
                if let objs = objects {
                    for object in objs {
                        self.feedData.append(object as! PFObject)
                    }
                    self.feedData = self.feedData.reverse()
                }
                NSOperationQueue.mainQueue().addOperationWithBlock { self.tableView.reloadData() }
            }
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.loadData(nil)
            self.title = "Quotezilla"
        }
    
        // MARK: - Table view data source
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return feedData.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(FeedTableViewController.cellID, forIndexPath: indexPath) as! QuoteTableViewCell
            cell.likesButton!.tag = indexPath.row // See how tag works with the above
            cell.contentTextView!.font = font
            cell.timeStampLabel!.font = font
            cell.publisherLabel!.font = font
    
            cell.contentTextView.alpha = 0.0
            cell.timeStampLabel.alpha = 0.0
            cell.publisherLabel.alpha = 0.0
    
            let q = feedData[indexPath.row]
            if let content = q.objectForKey("content") as? String {
                cell.contentTextView.text = content
            }
            else {
                cell.contentTextView.text = "Content not found!"
            }
            var dateFormatter = NSDateFormatter()
            dateFormatter.dateFormat = "EEEE, MMM d, h:mm a"
            cell.timeStampLabel.text = dateFormatter.stringFromDate(q.createdAt!)
    
            let votes = (q.objectForKey("votes") as? Int) ?? 0
            cell.likesLabel?.text = "\(votes)"
            let myObject = q.objectForKey("publisher") as? PFObject
            myObject?.fetchInBackgroundWithBlock {
                [unowned self]
                (object: PFObject?, error: NSError?) in
                NSOperationQueue.mainQueue().addOperationWithBlock {
                    if let foundUser = object as? PFUser {
                        cell.publisherLabel.text = foundUser.username
                        UIView.animateWithDuration(0.7) {
                            cell.contentTextView.alpha = 1.0
                            cell.timeStampLabel.alpha = 1.0
                            cell.publisherLabel.alpha = 1.0
                        }
                    }
                    else {
                        cell.publisherLabel.text = "Publisher not found!"
                    }
                }
            }
            return cell
        }
    }