i have searched a lot of examples and tutorials on how to run AFNetworking 2.0 synchronously and found only solutions for AFNetworking 1.0. What i have found: Can AFNetworking return data synchronously (inside a block)?
My example:
- (User *)getUserWithUsername: (NSString *) username andPassword: (NSString *) password {
NSDictionary *params = @{@"email": username, @"password": password};
[[DCAPIClient sharedClient] POST:@"login" parameters:params success:^(NSURLSessionDataTask * __unused task, id JSONResult) {
NSLog(@"JSON %@", JSONResult);
BOOL errorCode = [JSONResult objectForKey:@"error"];
if (!errorCode) {
self.username = [JSONResult objectForKey:@"name"];
// Fill the attributes
// self.email = .. a
} else {
// error with login show alert
}
} failure:^(NSURLSessionDataTask *__unused task, NSError *error) {
NSLog(@"error %@", error);
}];
// this does not work
//[[[DCAPIClient sharedClient] operationQueue] waitUntilAllOperationsAreFinished];
if (self.username == nil) {
return nil;
}
return self;
}
But this does not work, because if (self.username == nil)
is called first.
How can i get AFNetworking 2.0 lib run synchronously that i can return response?
DCAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient {
static DCAPIClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[DCAPIClient alloc] initWithBaseURL:[NSURL URLWithString:DCAPIBaseURLString]];
_sharedClient.responseSerializer = [AFJSONResponseSerializer serializer];
});
return _sharedClient;
}
You should not make an inherently asynchronous method synchronous, but instead make your call-site asynchronous as well.
That is, your method becomes asynchronous and provides a completion handler:
- (void) userWithUsername:(NSString *)username
password:(NSString *)password
completion:(completion_handler_t)completion;
where completion_handler_t
is a type definition and may be declared in the header file like this:
typedef void (^completion_handler_t)(User*, NSError*);
Note that using a typedef
is optional and may make your code more comprehensible.
Then you can use it as follows:
[self userWithUsername:username
password:password
completion:^(User* user, NSError*error){
// Check error; do something with user
...
}];
You can implement it as shown below:
- (void) userWithUsername:(NSString *)username
password:(NSString *)password
completion:(completion_handler_t)completion
{
NSDictionary *params = @{@"email": username, @"password": password};
[[DCAPIClient sharedClient] POST:@"login" parameters:params
success:^(NSURLSessionDataTask * __unused task, id JSONResult) {
NSLog(@"JSON %@", JSONResult);
BOOL errorCode = [JSONResult objectForKey:@"error"];
if (!errorCode) {
self.username = [JSONResult objectForKey:@"name"];
// Fill the attributes
// self.email = .. a
if (completion) {
completion(theUser, nil); // completion(self, nil)??
}
} else {
if (completion) {
completion(nil, error);
}
}
} failure:^(NSURLSessionDataTask *__unused task, NSError *error) {
if (completion) {
completion(nil, error);
}
}];
}