Waiting for completion block to complete in AFNetworking request

I make a JSON request with AFNetworking and then call [operation waitUntilFinished] to wait for the operation and success or failure blocks. But it seems to be true, but in the log messages I get "0", "3", "1" instead of "0", "1", "3"

NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://google.com"]]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; httpClient.parameterEncoding = AFFormURLParameterEncoding; NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"query", @"q", nil]; NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; NSLog(@"0"); AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, id JSON) { NSLog(@"1"); gotResponse = YES; } failure:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, NSError *error, id JSON) { NSLog(@"2"); gotResponse = YES; }]; NSLog(@"Starting request"); [operation start]; [operation waitUntilFinished]; NSLog(@"3"); 
+7
source share
4 answers

This works by using AFNetworking to configure requests, but by making a synchronous call and then handling completion locks manually. Very simple. AFNetworking does not seem to support this https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ , although the work around is fairly simple.

 #import "SimpleClient.h" #import "AFHTTPClient.h" #import "AFJSONRequestOperation.h" #import "AFJSONUtilities.h" @implementation SimpleClient + (void) makeRequestTo:(NSString *) urlStr parameters:(NSDictionary *) params successCallback:(void (^)(id jsonResponse)) successCallback errorCallback:(void (^)(NSError * error, NSString *errorMsg)) errorCallback { NSURLResponse *response = nil; NSError *error = nil; NSURL *url = [NSURL URLWithString:urlStr]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; httpClient.parameterEncoding = AFFormURLParameterEncoding; NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:[url path] parameters:params]; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; if(error) { errorCallback(error, nil); } else { id JSON = AFJSONDecode(data, &error); successCallback(JSON); } } @end 
+14
source

This should (almost) work. Your challenge

 NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; 

probably will not pass [url path] to the path: parameter. In AFNetworking land, this path is everything after the base url (for example, the base url could be “http://google.com” and the path “/ gmail” or something else).

Speaking of this, you probably should not do the asynchronous operation of the synchronous operation of blocking threads with waitUntilFinished, but I'm sure you have your own reasons ...;)

0
source

I had the same problem and found another solution. I had two operations that depend on each other, but can be loaded in parallel. However, the completion block of the second operation cannot be completed until the completion of the completion block of the first.

As Colin pointed out, this might be a poor choice for creating a web request block. This was important to me, so I did it asynchronously.

This is my decision:

 // This is our lock @interface SomeController () { NSLock *_dataLock; } @end @implementation // This is just an example, you might as well trigger both operations in separate // places if you get the locking right // This might be called eg in awakeFromNib - (void)someStartpoint { AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url1] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { // We're done, we unlock so the next operation can continue its // completion block [_dataLock unlock]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { // The request has failed, so we need to unlock for the next try [_dataLock unlock]; }]; AFJSONRequestOperation *operation2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url2] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { // The completion block (or at least the blocking part must be run in a // separate thread [NSThread detachNewThreadSelector:@selector(completionBlockOfOperation2:) toTarget:self withObject:data]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { // This second operation may fail without affecting the lock }]; // We need to lock before both operations are started [_dataLock lock]; // Order does not really matter here [operation2 start]; [operation1 start]; } - (void)completionBlockOfOperation2:(id)data { // We wait for the first operation to finish its completion block [_dataLock lock]; // It done, so we can continue // We need to unlock afterwards, so a next call to one of the operations // wouldn't deadlock [_dataLock unlock]; } @end 
0
source

Use delegate method call

Place the method inside the block that will call itself when loading / unloading is completed.

0
source

All Articles