0

Array returning a blank array when outside of the PFQuery. For some reason, the items are not being passed to the array when compiled.

class DriverViewController: UIViewController {
var placesArr : Array<Place> = []


    override func viewDidLoad() {
    super.viewDidLoad()
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)


    var query = PFQuery(className:"places")
    query.whereKey("username", equalTo:"[email protected]")
    query.findObjectsInBackgroundWithBlock {
        (objects: [AnyObject]?, error: NSError?) -> Void in

        if error == nil {
            println("Successfully retrieved \(objects!.count) scores.")

            if let objects = objects as? [PFObject] {
                for object in objects {
             let x = Place(aIdent: (object["Ident"] as! Int), aName: (object["name"] as! String), aAddress: (object["originAddress"] as! String), aCity: (object["originCity"] as! String), aCategoryName: (object["catName"] as! String), aLat: (object["aLat"] as! String), aLng: (object["aLng"] as! String))

                    self.placesArr.append(x)
                    println(placesArr) //****It works here and prints an array****
                }
            }
        } else {
            // Log details of the failure
            println("Error: \(error!) \(error!.userInfo!)")
        }
    }
 println(placesArr) //****But here it returns a blank array and this is where I need it to return an array****

3 Answers 3

4

This a very common misunderstanding relating to threading, the issue is what order events run:

// Runs 1st
query.findObjectsInBackgroundWithBlock {
    (objects: [AnyObject]?, error: NSError?) -> Void in
    // Runs 3rd
}
// Runs 2nd
println(placesArr)

The execution of the program doesn't halt when you call findObjectsInBackground, it finds objects: inBackground which means the heavy lifting of a network request is dispatched to a different queue so that the user can still interact with the screen. A simple way to do this would be to do:

var placesArray: [Place] = [] {
    didSet {
        // Do any execution that needs to wait for places array here.
    }
}

You can also trigger subsequent actions within the parse response block, I just personally find executing behavior dependent on a property update being executed in didSet to be a nice way to control flow.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Logan! The placing is important. For it to work, var placesArray: [Place] = [] { didSet { // Do any execution that needs to wait for places array here. } } Needs to go before the PFQuery.
2

Logan's answer is right in the money.

See my answer in this thread: Storing values in completionHandlers - Swift

I wrote up a detailed description of how async completion handlers work, and in the comments there is a link to a working example project the illustrates it.

1 Comment

I feel like I do one of these a day, such as this one yesterday stackoverflow.com/questions/30493949/…. I thought you had written a general purpose question and answer about this, but couldn't locate it as a reference.
1

query.findObjectsInBackgroundWithBlock is a block operation that performs in the background - it's asynchronous.

The line println(placesArr) actually executes before the block is finished - that's why you see nil there.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.