0

I found a lot of information concerning completionHandlers. However, I don't yet get how to handle it in this case. Maybe you can help me.

I'm trying to get a list of all Facebook friends and store it in an array.

getFacebookFriends

func getFacebookFriends() -> NSMutableArray
{

    var retFriendIDs:NSMutableArray = []

    FBRequestConnection.startForMyFriendsWithCompletionHandler {
        (connection:FBRequestConnection!, result: AnyObject!, error:NSError!) -> Void in

        if (error == nil){
            var resultdict = result as! NSDictionary
            self.data = resultdict.objectForKey("data") as! NSArray

            var friendIDs:NSMutableArray = []
            for (var i = 0; i < self.data.count; i++) {
                let valueDict : NSDictionary = self.data[i] as! NSDictionary
                let id = valueDict.objectForKey("id") as! String
                friendIDs.addObject(id as String)
            }
            retFriendIDs = friendIDs
        }
    }
    return retFriendIDs
}

As this is a completionHandler I understand that the return fires before completion of the block. But how do I achieve a return to use the list in this function for example?

findFacebookFriendsInBackend

func findFacebookFriendsInBackend() -> [AnyObject]{
    println("findFacebookFriendsInBackend")
    var retFriends:[AnyObject] = []

    let fbFriends:NSMutableArray = getFacebookFriends()

    var friendQuery = PFUser.query()
    // look for friends in Parse
    friendQuery!.whereKey("fbId", containedIn: fbFriends as [AnyObject])

    friendQuery!.findObjectsInBackgroundWithBlock{
        (friends, error) -> Void in
        if error == nil {
            retFriends = friends as [AnyObject]!
        }
    }
    return retFriends
}

And then use it in a simple function like this:

iterateOverFriends

func iterateOverFriends(friends:[AnyObject]!){
    for i in friends {
        doSomething(i)
    }
}

To call

iterateOverFriends(findFacebookFriendsInBackend())
Akaino
  • 1,025
  • 6
  • 23

1 Answers1

1

Short answer: You don't. Not possible. With an async method, the result doesn't exist at the time when you return.

You have to adjust your thinking.

Rewrite this method:

func findFacebookFriendsInBackend() -> [AnyObject]{

As something like this instead:

func findFacebookFriendsInBackend(#completion:
  (friendsArray: [AnyObject]) -> ())

In the new form it takes a block as a parameter. Write the function so that it invokes the block once it has built the array of friends.

The new call would look like this

findFacebookFriendsInBackend()
{
  (friendsArray) -> () in
  iterateOverFriends(friendsArray)
}

(When you have a function that takes a closure as the final parameter, you can call it with the closure outside the parenthesis.)

I wrote a long answer, including a working example project, in this thread.

Community
  • 1
  • 1
Duncan C
  • 128,072
  • 22
  • 173
  • 272