Andrei P
Andrei P

Reputation: 13

GCD dispatch_sync doesn't finish executing in order

I have a method which helps me sync my local standardUserDefaults with a Web Service. First, I need to make sure that data has been synced successfully, then I can let the method return. The problem I am currently striving to resolve is that I can't get the GCD to execute & finish the tasks in a certain order: firstly POSTing to the web service and secondly returning.

The problem is that the second dispatch_sync task finishes execution first, then comes the first dispatch_sync task. How to I make sure the execution happens as scheduled? Is this a special case because of the NSURLSessionDataTask?

Thanks a lot!

-(void) syncLocalStorageToMMUsersDB:(void(^)(bool success))handler
{
__block bool fb_sync_success = 0;

dispatch_queue_t requestQueue = dispatch_queue_create("com.micromorts.request", DISPATCH_QUEUE_SERIAL);


//if logged in with Facebook, then sync it
if ([_defaults stringForKey:MMFBIdPrefsKey]) {
  // Start NSURLSession
  NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
  NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];

  // POST parameters
  NSURL *url = [NSURL URLWithString:@"http://THE.URL.GOES.HERE"];
  NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
  NSString *params = [POST PARAMS GO HERE];
  [urlRequest setHTTPMethod:@"POST"];
  [urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];

  // NSURLSessionDataTask returns data, response, and error

  NSURLSessionDataTask *dataTask =[defaultSession dataTaskWithRequest:urlRequest
    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        // Handle response
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        NSInteger statusCode = [httpResponse statusCode];
        if(error == nil) {
          if (statusCode == 404) {
              NSLog(@"MMAuth.m :: syncLocalStorageToMMUsersDB FB :: FB User not found");
              fb_sync_success = false;

          } else if (statusCode == 200) {
              NSLog(@"MMAuth.m :: syncLocalStorageToMMUsersDB FB :: Successfully synced ");
              fb_sync_success = true;

          } else {
          NSLog(@"MMAuth.m :: syncLocalStorageToMMUsersDB FB :: Sync fail ");
              fb_sync_success = false;
          }
        }
    }
  ];
  //This should finish EXECUTING first
  dispatch_sync(requestQueue, ^{
      [dataTask resume];
  });
}

//This should finish EXECUTING second
dispatch_sync(requestQueue, ^{

    if (fb_sync_success){
       NSLog(@"SUCCESS");
    } else {
       NSLog(@"FAILED");
    }

});
}

Upvotes: 1

Views: 296

Answers (1)

bbum
bbum

Reputation: 162722

If the call to [dataTask resume]; is asynchronous, then that dispatch_sync() will return immediately after -resume executes and then the subsequent dispatch_sync() will be enqueued and executed immediately after (but before the data is loaded).

Move your SUCCESS/FAILED logic into the completion handler block; that is why completion handlers exist.

Upvotes: 3

Related Questions