0

I don't understand why the arrays become empty after the query with block. I did some research and it's most likely because I need a completion handler, but I can't figure out how to implement it in this case. Can I just add an activity indicator until the method is done?

var usernamesFollowing = [""]
var useridsFollowing = [""]

func refresh(completion: (Bool)){

    //find all users following the current user
    var query = PFQuery(className: "Followers")
    query.whereKey("following", equalTo: PFUser.currentUser()!.objectId!)
    query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in

        if error == nil {
            //remove all from arrays
            self.usernamesFollowing.removeAll(keepCapacity: true)
            self.useridsFollowing.removeAll(keepCapacity: true)

            //get all userIds of following current user and add to useridsFollowing array
            if let objects = objects {

                for userId in objects {

                    var followerId = userId["follower"] as! String
                    self.useridsFollowing.append(followerId)

                    //get usernames from followerId and add to usernamesFollowing array
                    var query = PFUser.query()
                    query!.whereKey("objectId", equalTo: followerId)
                    query!.findObjectsInBackgroundWithBlock({ (objects2, error) -> Void in

                        if let objects2 = objects2 {
                            for username in objects2 {
                                var followerUsername = username["username"] as! String
                                self.usernamesFollowing.append(followerUsername)
                            }
                        }
                        //WORKS. usernamesFollowing array is now full.
                        println(self.usernamesFollowing)
                    })
                    //BROKEN. usernamesFollowing array is now empty outside of block.
                    println(self.usernamesFollowing)

                }

            }
        }
        //WORKS. useridsFollowing is now full.
        println(self.useridsFollowing)
    })

    //BROKEN. usernamesFollowing is now empty outside of block.
    println(self.usernamesFollowing)
}
rici
  • 234,347
  • 28
  • 237
  • 341
Petruc
  • 23
  • 4
  • 2
    It's because `findObjectsInBackgroundWithBlock` is async. If you println() also a different number for each case, you'll see that they are not called in the order that you think. – Larme Sep 03 '15 at 15:33

1 Answers1

0

To elaborate on Larme's point - asynchronous methods return immediately, and dispatch the work into another queue. To put this in context, consider your two println statements:

println(self.usernamesFollowing) //1. inside async fetch closure
println(self.usernamesFollowing) //2. outside async fetch closure

The asynchronous method will take your closure and dispatch it on to a different queue. After doing so, it returns immediately, and continues to execute your code, which goes to your 2nd println statement right away. In this situation, your second println statement will actually print before your first.

If possible, do all your data manipulations within the block. It'll save you a lot of work. If you must offload the objects outside of the block, consider using NSOperations, which is perfectly equipped to deal with that type of scenario.

Kelvin Lau
  • 6,373
  • 6
  • 34
  • 57