Reputation: 2585
I am very new to the concept of asynchronous programming, but I get the general gist of it (things get run in the backround).
The issue I'm having is I have a method which utilizes AFNetworking 2.0 to make an HTTP post request, and it works for the most part.
However, I can't figure out how to get the method to actually return the value received from the response as the method returns and THEN gets the value from the response.
-(int) registerUser
{
self.responseValue = 000; //Notice I set this to 000 at start of method
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *parameters = @{ @"Username": @"SomeUsername" };
[manager POST:@"http://XXX/register"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(@"JSON: %@", responseObject);
NSError *err = nil;
self.responseValue = [[responseObject objectForKey:@"res"] intValue];
//Note: This^ value returns 99 and NSLogs confirm this
}
failure:^(AFHTTPRequestOperation *operation, NSError *err)
{
NSLog(@"Error: %@", err);
}];
return self.responseValue; //This will return 000 and never 99!
}
Whats the 'proper' way to handle this situation? I've heard whispers of using a 'callback', but I don't really understand how to implement that in this situation.
Any guidance or help would be awesome, cheers!
Upvotes: 1
Views: 114
Reputation: 136
Check this one and use search ;-))
Getting variable from the inside of block
its a lot of duplicates already!
:-)
Upvotes: 1
Reputation: 437381
The issue is that the POST
runs asynchronously, as you point out, so you are hitting the return
line well before the responseValue
property is actually set, because that success
block runs later. Put breakpoints/NSLog
statements in there, and you'll see you're hitting the return
line first.
You generally do not return
values from an asynchronous methods, but rather you adopt the completion block pattern. For example:
- (void)registerUserWithCompletion:(void (^)(int responseValue, NSError *error))completion
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *parameters = @{ @"Username": @"SomeUsername" };
[manager POST:@"http://XXX/register"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(@"JSON: %@", responseObject);
int responseValue = [[responseObject objectForKey:@"res"] intValue];
if (completion)
completion(responseValue, nil);
}
failure:^(AFHTTPRequestOperation *operation, NSError *err)
{
NSLog(@"Error: %@", err);
if (completion)
completion(-1, err); // I don't know what you want to return if it failed, but handle it appropriately
}];
}
And then, you could use it as follows:
[self registerUserWithCompletion:^(int responseValue, NSError *error) {
if (error)
NSLog(@"%s: registerUserWithCompletion error: %@", __FUNCTION__, error);
else
NSLog(@"%d", responseValue);
// do whatever you want with that responseValue here, inside the block
}];
// Needless to say, don't try to use the `responseValue` here, because
// `registerUserWithCompletion` runs asynchronously, and you will probably
// hit this line of code well before the above block is executed. Anything
// that is dependent upon the registration must called from within the above
// completion block, not here after the block.
Note, I'd suggest you retire that responseValue
property you had before, because now that you're using completion blocks, you get it passed back to you via that mechanism, rather than relying on class properties.
Upvotes: 1