0

I want to query using Parse to add strings to an array. Then I want to put those strings into the cells of my UITableView. However, every time I run the app nothing seems to appear on my table. Here is my code if someone could help explain some of the reasons that it may not be appearing

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate  {

@IBOutlet weak var tableView: UITableView!


var friendsArray: [String] = []

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

    var usrname = currentUser?.username
    var query = PFQuery(className:"Relation")
    query.whereKey("Sender", equalTo : usrname!)
    query.findObjectsInBackgroundWithBlock {
        (objects: [AnyObject]?, error: NSError?) -> Void in

        if error == nil {
            // The find succeeded.
            //println("Successfully retrieved \(objects) scores.")
            // Do something with the found objects
            if let objects = objects as? [PFObject] {
                for object in objects {
                    var friendName = object["Friend"] as! String
                    println(friendName)
                    self.friendsArray.append(friendName)
                }
            }
        }
        else {
            // Log details of the failure
            println("Error: \(error!) \(error!.userInfo!)")
        }
    }


}


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return friendsArray.count
}

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

    var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell

    cell.textLabel?.text = self.friendsArray[indexPath.row]

    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

}
gutch
  • 6,959
  • 3
  • 36
  • 53
Justin
  • 243
  • 5
  • 15

9 Answers9

1

You need to call [self.tableView reloadData]; in the completion block of the findObjectsInBackground: call.

socaljoker
  • 304
  • 2
  • 11
0

When you call findObjectsInBackgroundWithBlock its doing exactly what it name says, specifically its running in the background.

Meanwhile while its running in the background your table view code continues to run in the foreground, effectively in parallel.

So your viewDidLoad function will exit and numberOfRowsInSection will be called next, but at that time if findObjectsInBackgroundWithBlock has not yet finished then friendsArray.count will be 0.

Lucas Huang
  • 3,998
  • 3
  • 20
  • 29
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • So what can I do to fix this? – Justin May 21 '15 at 20:31
  • Similar to this same question yesterday. They are using asynchronous code just in a different place to you. http://stackoverflow.com/questions/30361517/asynchronous-tableviewcell-data/30361658#30361658. The principle and solution options are similar. – Gruntcakes May 21 '15 at 20:32
  • Im confused how I can make sure Im running the CellforRowAtIndexPath function after ViewdidLoad, because I would think ViewDidLoad or even ViewDidAppear would all happen first – Justin May 21 '15 at 20:34
  • In your case when the block completes you could refresh the table. – Gruntcakes May 21 '15 at 20:34
  • How should I do this? – Justin May 21 '15 at 20:35
0

The app does not know when your data will be returned so that you have to explicitly to refresh the UITableView once you have successfully received the data. Use [self.tableView reloadData] to reload the UITableView later on.

The UITableView will only load once when UIViewController gets loaded. Unless, you have already have data the time when UIViewController loads. Otherwise, the number of rows will be 0 at the first time and the delegate method cellForRowAtIndexPath will not be called.

findObjectsInBackgroundWithBlock is an async call when you take a look at the documentation. It's not like its literal meaning that it's running in the background. It means that it won't block the current thread so that users can still have interaction with the application.

Lucas Huang
  • 3,998
  • 3
  • 20
  • 29
  • @Kasik Async means that it will not wait for the response to come back on the current thread. It does not mean that it's dispatched to another thread. – Lucas Huang May 21 '15 at 23:10
0

At the end of your if error == nil{...} statement, load your table data like this:

if error == nil{
  //All that other stuff...
  tableView.reloadData()
}

Also make sure your tableView has its delegate and datasource connected to your view controller. This may require putting this in viewDidLoad:

tableView.delegate = self
tableView.datasource = self

I also find it peculiar that your tableView is declared as weak, but that may not be relevant.

Try these things and let us know if you're still having trouble. Good luck! :)

Clifton Labrum
  • 13,053
  • 9
  • 65
  • 128
0

just try these things. it will help you after you get array of element make reload the uitableView. if you use storyboard check the datasource outlet it you did not use storyboard or xib, then you set datasource in coding wisse

parthiban
  • 95
  • 9
0

hi you can use like this

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

{


    let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell


    cell.textLabel?.text = app.str[indexPath.row]




     print(" cell \(cell.textLabel?.text!)")


    return cell


}

TableOutLet.reloadData()

0
  • Conform your tableView to its delegate and datasource by written below two lines in your viewDidLoad() after super.viewDidLoad():

    tableView.datasource = self tableView.delegate = self

  • Then update this code as below :

    if let objects = objects as? [PFObject] { for object in objects { var friendName = object["Friend"] as! String println(friendName) self.friendsArray.append(friendName) } tableView.reloadData() }

  • After that in tableView delegate methods return self.friendsArray.count for numberOfRows() method and also put your code in cellForRow also.

Ashvini
  • 342
  • 3
  • 11
0

Just place your line after appending elements in array.

override func viewDidLoad() {
super.viewDidLoad()


var usrname = currentUser?.username
var query = PFQuery(className:"Relation")
query.whereKey("Sender", equalTo : usrname!)
query.findObjectsInBackgroundWithBlock {
    (objects: [AnyObject]?, error: NSError?) -> Void in

    if error == nil {
        // The find succeeded.
        //println("Successfully retrieved \(objects) scores.")
        // Do something with the found objects
        if let objects = objects as? [PFObject] {
            for object in objects {
                var friendName = object["Friend"] as! String
                println(friendName)
                self.friendsArray.append(friendName)
            }
        }
    }
    else {
        // Log details of the failure
        println("Error: \(error!) \(error!.userInfo!)")
    }
}
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}

Or you can reload table once your final array up-to-date

Anjali jariwala
  • 410
  • 5
  • 15
-1

As mentionded by another hint you need to call reloadData but you need to call it in main thread to see result as soon as possible

dispatch_async(dispatch_get_main_queue()) {self.tableView.reloadData()}
Kasik
  • 169
  • 1
  • 8
  • He did not dispatch that block of code to another queue, it's just running on the main thread. So, `self.tableView.reloaddata()` is enough – Lucas Huang May 21 '15 at 21:46
  • @LucasHuang I don't know PFQuery but findInBackground does not sound to me as main thread. It can be implemented in way that the callback is performed on main thread but it is unusual. And on the other hand using dispatch_async is almost free of charge and it could not makes thinks worse. – Kasik May 21 '15 at 21:55
  • The reason they implemented always in main thread because developers can dispatch into another queue on their will. If Parse developers put it into other queues, than it's not developers to control it. I don't think that's their style either. – Lucas Huang May 21 '15 at 23:06
  • `Finds objects asynchronously and calls the given block with the results.` They did not say anything on the thread. However, if the main thread is not that busy, iOS will put the task back to main thread as well. So, it's not really necessary for you to dispatch back to main thread. – Lucas Huang May 21 '15 at 23:08
  • http://stackoverflow.com/questions/21122842/whats-the-difference-between-synchronous-and-asynchronous-calls-in-objective-c This post helps a lots. You can consider to change your answer. Although it won't hurt to use this way but not that necessary. – Lucas Huang May 21 '15 at 23:12
  • Thanks for explanation. I'm aware of GCD. But invoking async on main queue (dispatch_async(dispatch_get_main_queue())) doesn't make sense because you just postpone stucking of UI. And I not aware how to invoke callback on current queue without using deprecated function. Are you aware how to solve it? – Kasik May 22 '15 at 00:05
  • Sorry, I don't get your question. Can you describe in another way? – Lucas Huang May 22 '15 at 09:45
  • Let assume that they are using `dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))` for processing background logic and at the end of the processing they need to somehow invoke the callback closure. How their assure invoking this callback closure on same queue as been used for invoking they function. There is easy way when closure should be always executed in main queue `dispatch_async(dispatch_get_main_queue()) `. But they don't mentioned that closure is always invoked on main queue. So how they invoke the closure on invoker current queue? – Kasik May 22 '15 at 09:54
  • I think you are overthinking it. Parse developers can dispatch to the concurrent queues underlying but it's not necessary because the developers can dispatch themselves and put it back to whatever threads they want. – Lucas Huang May 22 '15 at 17:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78574/discussion-between-kasik-and-lucas-huang). – Kasik May 22 '15 at 20:48