Reputation: 2989
I'm using AFNetworking for POST requests. I need to wait until the completion block is done to return data, and I've run into problems.
I had a solution that was working until I switched to AFNetworking:
int i = 0;
while (!done)
{
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
i++;
NSLog(@"While Loop:%i", i);
if (i == 149) //request timed out
done = YES;
}
Now, the solution works sporadically. Sometimes it completes with NSLog(@"While Loop:%i", i);
only logging 1 or 2, but sometimes it logs until 149 and times out. It seems like the NSRunLoop
sometimes runs in a different thread, but sometimes runs on the same thread blocking my request.
Here's the code that I currently have:
- (id)postRequestWithBaseURLString:(NSString *)baseURLString function:(NSString *)function parameters:(NSDictionary *)parameters
{
if (baseURLString)
function = [baseURLString stringByAppendingString:function];
__block BOOL done = NO;
__block id returnObject = nil;
[self.manager POST:function parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(@"Success: %@", responseObject);
done = YES;
returnObject = responseObject;
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"Error: %@", error);
done = YES;
}];
[manager.operationQueue waitUntilAllOperationsAreFinished];
int i = 0;
while (!done)
{
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
i++;
NSLog(@"While Loop:%i", i);
if (i == 149) //request timed out
done = YES;
}
return returnObject;
}
I've tried doing a dispatch_group
without success. Help?
EDIT
Ok, I've got more info. My solution works when I first call the API (for example, when I first call a ViewController
), but not afterwards. Perhaps, after the view is loaded, the while loop is called on the same thread as the API call, therefore blocking it?
This also seems likely, since the NSLog(@"Success: %@", responseObject);
is called almost exactly after timeout happens.
Upvotes: 3
Views: 2977
Reputation: 2989
Found an elegant solution online. I created my own completion block. Here's what I did:
+ (void)jsonRequestWithBaseURL:(NSString *)baseURL function:(NSString *)function parameters:(NSDictionary *)parameters completion:(void (^)(NSDictionary *json, BOOL success))completion
{
if (baseURL)
function = [baseURL stringByAppendingString:function];
NSLog(@"%@ function:%@, parameters:%@", self.class, function, parameters);
[AFHTTPRequestOperationManager.manager POST:function parameters:parameters success:^(AFHTTPRequestOperation *operation, id jsonObject)
{
//NSLog(@"Success: %@", jsonObject);
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
if (completion)
completion(jsonDictionary, YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"%@ AFError: %@", self.class, [error localizedDescription]);
completion(nil, NO);
}];
}
Then, when I need to call the method, I do this:
NSDictionary *parameters = @{@"email":@"[email protected]", @"password":@"mypassword"};
[ZAPRootViewController jsonRequestWithBaseURL:@"http://www.myserver.com/" function:@"login.php" parameters:parameters completion:^(NSDictionary *json, BOOL success)
{
if (success)
{
//do something
}
}];
Upvotes: 5