Question

I have a class which manages all calls to an api. It has a method to manage this, lets call this callAPIMethod:

This method accepts a success and fail block.

Inside this method, I call uploadTaskWithRequest to make a call to an API. Within the uploadTaskWithRequest completion handler I'd like to (depending on the result) pass results back through to either the success or fail blocks.

I'm having some issues with this. It works and is keeping everything super tidy but when I call callAPIMethod using the success/fail blocks it's locking up the UI/MainThread rather than being asynchronous as I'd expect.

How should I go about implementing this pattern? Or is there a better way to go about it?

I don't need to support pre-iOS7.

Thanks

Edit: Basic implementation discussed above.

- (void)callApiMethod:(NSString *)method withData:(NSString *)requestData as:(kRequestType)requestType success:(void (^)(id responseData))success failure:(void (^)(NSString *errorDescription))failure {
    [redacted]
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session uploadTaskWithRequest:request
                                                       fromData:postData
                                              completionHandler:
                                  ^(NSData *data, NSURLResponse *response, NSError *error) {
                                      if (error) {
                                          failure(error.description);
                                      } else {
                                          NSError *jsonError;
                                          id responseData = [NSJSONSerialization
                                                             JSONObjectWithData:data
                                                             options:kNilOptions
                                                             error:&jsonError];
                                          if (jsonError) {
                                              failure(jsonError.description);
                                          } else {
                                              success(responseData);
                                          }
                                      }
                                  }];

    [task resume];
}

CallAPI method, used as follows (from a UITableViewController):

[apiController callApiMethod:@"users.json?action=token"
                    withData:loginData
                          as:kRequestPOST
                     success:^(id responseData) {
                         if ([responseData isKindOfClass:[NSDictionary class]]) {
                             if ([responseData objectForKey:@"token"]) {
                                 //Store token/credentials
                             } else if ([responseData objectForKey:@"error"]) {
                                 //Error
                                 [self displayErrorMessage:[responseData objectForKey:@"error"]];
                                 return;
                             } else {
                                 //Undefined Error
                                 [self displayErrorMessage:nil];
                                 return;
                             }
                         } else {
                             //Error
                             [self displayErrorMessage:nil];
                             return;
                         }

                         //If login success

                     }
                     failure:^(NSString *errorDescription) {
                         [self displayErrorMessage:errorDescription];
                     }];
Was it helpful?

Solution

Your NSURLSession code looks fine. I'd suggest adding some breakpoints so you can identify if it is deadlocking somewhere and if so, where. But nothing in this code sample would suggest any such problem.

I would suggest that you ensure that all UI calls are dispatched back to the main queue. This NSURLSessionUploadTask completion handler may be called on a background queue, but all UI updates (alerts, navigation, updating of UIView controls, etc.) must take place on the main queue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top