0

i'm trying to make an iOS App that communicates with an API using AFHTTPClient. The first step is to authentificate the user, to do so, i use this code:

-(void)authorize
{
    NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"login.php" parameters:@{@"login": account.username, @"passwd":account.password}];

    AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [httpClient setDefaultHeader:@"Token" value:[[operation.response allHeaderFields] objectForKey:@"CSRF-Token"]];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@",error.localizedDescription);
    }];
    [httpClient enqueueHTTPRequestOperation:operation];
    [httpClient.operationQueue waitUntilAllOperationsAreFinished];
}

As you can see, my code gets a token from the server response and sets it as a default header for all future requests.

I then proceed to other requests using - (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:success failure:failure

But when i used the debugger, i found out that those other requests where executed before the authorize operation was completed, therefore they failed because they didn't have the auth token. I added [httpClient.operationQueue waitUntilAllOperationsAreFinished]; but it doesn't seem to work...

Thank you for your help

Abel
  • 315
  • 1
  • 4
  • 18
  • Don't use `wait` until anything functions. Those block app until the network connection finishes. Just put the necessary code in your `success` block and call `displayNextView` after it's done. – Keith Smiley Feb 18 '13 at 01:15

1 Answers1

2

Use a dispatch semaphore.

-(void)authorize
{
    dispatch_semaphore_t done = dispatch_semaphore_create(0);
    NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"login.php" parameters:@{@"login": account.username, @"passwd":account.password}];

    AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [httpClient setDefaultHeader:@"Token" value:[[operation.response allHeaderFields] objectForKey:@"CSRF-Token"]];
        dispatch_semaphore_signal(done);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@",error.localizedDescription);
    }];
    [httpClient enqueueHTTPRequestOperation:operation];
    [httpClient.operationQueue waitUntilAllOperationsAreFinished];
    dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
}

Note that this will block the method from returning, so you need to make sure it's not on the main/UI thread.

Kevin
  • 53,822
  • 15
  • 101
  • 132
  • What do you mean by blocking the method from returning ? – Abel Feb 17 '13 at 20:45
  • I tried using it like this: `dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ [api authorize]; }); [api requestMethod:@"users"];` But it still doesn't work, the requestMethod is called before – Abel Feb 17 '13 at 20:51
  • You have to make the subsequent requests in the same thread (or blocked by a lock/semaphore: `^{[api authorize]; [api doOtherRequests];}`. If needed, you could create a queue and just queue up methods until the authorize call is done. – Kevin Feb 17 '13 at 21:44
  • Ok but when will the semaphore be notified that my operation is complete ? – Abel Feb 18 '13 at 16:54
  • The semaphore is notified by the signal (`dispatch_semaphore_signal`). – Kevin Feb 18 '13 at 17:47