1

I have multiple methods, each with nested loops and facebook requests. There is an array of X id's and each method loops through each id, makes a request for that id then does stuff with the result data.

I need to be notified when each method has completed... ie, when the method has finished looping through all the id's in the array, making the facebook request for each, received the results and finished its tasks with the resulting data. I can't seem to figure out how to make this happen. here are examples of the methods:

- (void)runLoopForFacebookFriendsContent1 {

    for (NSString *fbIdStr in self.fbIdsArr){
        FBRequest *fbRequest = [FBRequest requestWithGraphPath:graphPathString parameters:nil HTTPMethod:@"GET"];
        [fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
            if (error) {
                //show alert
            } else {
                //Do stuff with the resulting data
            }
        }];
    }    
}

- (void)runLoopForFacebookFriendsContent2 {

    for (NSString *fbIdStr in self.fbIdsArr){
        FBRequest *fbRequest2 = [FBRequest requestWithGraphPath:graphPathStringNumber2 parameters:nil HTTPMethod:@"GET"];
        [fbRequest2 startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
            if (error) {
                //show alert
            } else {
                for (PF_FBGraphObject *obj in [result objectForKey:@"data"]){
                    NSLog(@"facebook result:  %@",result);
                        NSMutableDictionary *dict          = [[NSMutableDictionary alloc]init];
                        [dict setValue:@"type2" forKey:@"ContentType"];
                        [dict setValue:obj forKey:@"data"];
                        [self.theFacebookDataArray addObject:dict];
                }
            }
        }];
    }    
}

I call these methods in viewWillAppear. is there a way to setup some sort of completion handler to put the call for these methods inside? and then post an NSNotification when they are all done?

Daniel McCarthy
  • 1,406
  • 2
  • 13
  • 19

3 Answers3

1

One option is to take a look at the ReactiveCocoa framework. I find it helps tremendously with this kind of pattern, after you get past a bit of a learning curve.

The following is an example directly from the linked file:

// Perform 2 network operations and log a message to the console when they are
// both completed.
//
// +merge: takes an array of signals and returns a new RACSignal that passes
// through the values of all of the signals and completes when all of the
// signals complete.
//
// -subscribeCompleted: will execute the block when the signal completes.
[[RACSignal 
    merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]] 
    subscribeCompleted:^{
        NSLog(@"They're both done!");
    }];

You could adapt this to the Facebook SDK fairly easily.

MattP
  • 1,920
  • 1
  • 15
  • 22
  • thanks for the response, Ill check out Reactive. The problem isn't really with facebook & know when the server calls are done... I think it's more about knowing when all the nested loops are done iterating. but I'll look into this to see if there is some way to setup a notification system for nested loop completion. – Daniel McCarthy Mar 09 '13 at 14:03
1

This behavior is expected since you are calling dispatch_group_enter and then instantly calling dispatch_group_leave which means the group has nothing to wait for.

You should call dispatch_group_enter before every block and call dispatch_group_leave at the end of every block.

Check the accepted answer here: Wait until multiple networking requests have all executed - including their completion blocks

Update: For the given example, you can call dispatch_group_enter before every call to startWithCompletionHandler:, and call dispatch_group_leave at the end of the completion block:

for (...) {
    FBRequest *fbRequest = ...;
    dispatch_group_enter(group);
    [fbRequest startWithCompletionHandler:^(...) {
        ...
        dispatch_group_leave(group);
    }
}
Community
  • 1
  • 1
Hejazi
  • 16,587
  • 9
  • 52
  • 67
  • this is exactly the problem though... I don't know where to call dispatch_group_leave. The code above was just to show the idea I had been trying... not the only thing i've tried. I've placed dispatch_group_leave everywhere I can think of, with no success. If I just put it as the last line of each method, doesn't work & notify happens before server calls are done. And I cant put it in a completion block for the server calls, cuz the server call is happening in a loop through different id's, so group_leave there would bump on 1st iteration. – Daniel McCarthy Mar 09 '13 at 14:01
  • where or how, with the above code, could I place dispatch_group_leave in order to have it leave after the entire method is done? meaning after each iteration of each nested loop? Is it possible to put the call to the method (from viewdidappear) inside a block? something like 'blah_blah_completion(block^{ [self runLoopMethod1]; });' ??? – Daniel McCarthy Mar 09 '13 at 14:08
  • I'v added more details, check the answer again. – Hejazi Mar 10 '13 at 17:40
  • I see what your saying, and i've played around with it, but I can't seem to get it to do what I need to do. I need to know or be notified when the entire method is finished... ie, when the entire series of nested for loops have completed. I'll try to update the question to be shorter and more clear – Daniel McCarthy Mar 13 '13 at 01:20
1

Didn't want to have to answer my own question... don't really like doing that, and was hoping for a more elegant solution... but it doesnt seem to be coming and someone even downvoted the question. So i'm just going to post my solution and close the question out. If you end up with a similar problem and are reading this, I dealt with it by:

creating 2 int's for each method. One int is immediately set with the count of the array being iterated through. at the end of each iteration, I am posting an NSNotification. In the NSNotification handler method, i am ++ incrementing the second int & each time running an if condition, checking to see if they match.

It's a pain to keep track of all these when there are many methods like this happening... So if anyone ever finds a better solution, I'd love to hear it. Thanks to everyone who answered and tried to be helpful, I appreciate it!

Daniel McCarthy
  • 1,406
  • 2
  • 13
  • 19