rohaldb
rohaldb

Reputation: 588

CellForRowAtIndexPath called before ViewWillAppear finished running

I have an application that pulls information from a Parse database, and displays it in a UITableView. I pull the information from parse in the viewWillAppear function, and i display it in the tableView(cellForRowAtIndexPath) function. Sometimes i receive an error because the array that stores the Parse information has a length of 0, and i try to access information at an index outside of the bounds of the array. I believe this is because the cellForRowAtIndexPath is getting called before the viewWillAppear is finished running. Is this possible or is my error definitely coming from somewhere else?

EDIT: The error does not occur every time, and i cannot find a way to reproduce it

override func viewWillAppear(animated: Bool) {

    //begin ignoring events until the information is finished being pulled
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()

    resultsArray.removeAll(keepCapacity: false)

    //run query
    let query = PFQuery(className: "Answers")
    query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in

        if let objects = objects {

                    //append information to the resultsArray 
                }
            }
            self.tableView.reloadData()
        }
    }
    //information is now pulled, so allow interaction 
   UIApplication.sharedApplication().endIgnoringInteractionEvents()

}


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

    // THIS IS WHERE THE ERROR OCCURS
    resultsArray[indexPath.row].imageFile.getDataInBackgroundWithBlock { (data, error) -> Void in

        //set image within cell
    }
    return cell
}

Upvotes: 3

Views: 2039

Answers (3)

Paulw11
Paulw11

Reputation: 114875

I would suggest that you load your data from Parse into a temporary array and then assign this to your property array right before you call reloadData - this will avoid any potential race conditions and remove the need for the removeAll which is potentially a big part of your problem;

override func viewWillAppear(animated: Bool) {

    //begin ignoring events until the information is finished being pulled
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()



    //run query
    let query = PFQuery(className: "Answers")
    query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in

        var localArray=[SomeType]()

        if let objects = objects {

                    //append information to the localArray 
                }
            }
            self.resultsArray=localArray
            self.tableView.reloadData()
        }
    }
    //information is now pulled, so allow interaction 
   UIApplication.sharedApplication().endIgnoringInteractionEvents()

}

Upvotes: 1

SeanChense
SeanChense

Reputation: 846

Actually if your callback not access to self.tableView, everything will go on as you think as usual. You can have a try.

It happened to me when I access to the view on the screen in init method viewDidLoad method called before init ends.

Anyway, you should know that fact. And you access to your tableView in callback (called before viewWillAppear finishing) which needs cellForRowAtIndexPath.

Upvotes: 0

OhadM
OhadM

Reputation: 4803

Looks like in viewWillAppear you have a background block findObjectsInBackgroundWithBlock that has some work to do in a different thread (AKA off the main thread), that means that viewWillAppear will finish while the block will get a callback.

This explains why cellForRowAtIndexPath is being called after viewWillAppear finishes, because of the callback block.

That means that everything is alright and viewWillAppear actually do finish a legit "run".

You can actually put a breaking point inside the callback method (in viewWillAppear) and a breaking point inside cellForRowAtIndexPath and see when the callback happens while cellForRowAtIndexPath is being called.

If you need a different method from Parse perhaps you should look in their documentation.

Upvotes: 0

Related Questions