objective-cwaitnsurlsessiontask

Force wait for NSURLSessionDataTask completion


I'm making a URLRequest that sends attempted login information and waits for a response from the web service to find out if the user can/cannot log in.

The way I was hoping to do this was by having the user type in his username & password into two text fields and then press a button, which would call the function below. This function would start an NSURLSessionDataTask and construct a struct with the boolean success/failure of the login and an NSString with the corresponding error message (if any).

The problem is that my function returns the struct before my NSURLSessionDataTask's completion block has finished executing. Is there a way for me to force my program to wait until this task either times out or completes? Alternatively, can I push execution of the completion block onto the main thread & before the function returns?

Thanks! Please let me know if there are any clarifications I need to make!

(Also, I have seen some similar questions circulating around StackOverflow that mention GCD. Is this an overkill solution? None of those questions seem to be talking about quite the same thing, or do so on a level that is higher than my current understanding. I am still very new to Objective-C)

- (struct RequestReport) sendLoginRequest: (NSString*) username withPassword:  (NSString *) password

... (creating the request & setting HTTP body)

NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error){

    NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData: data options:0 error:nil];

    success = (BOOL)jsonObject[@"success"];
    statusText = (NSString *) jsonObject[@"errors"];

}];

[dataTask resume];

struct RequestReport rr;
rr.status = statusText;
rr.success = success;

return rr;

Solution

  • Your method should look like this:

    - (void) sendLoginRequest:(NSString*) username withPassword:(NSString *) password callback:(void (^)(NSError *error, BOOL success))callback
        {
        NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error){
            if (error) {
                // Handle error
            }
            else {
               callback(error, YES);
           }
      }];
    
        [dataTask resume];
    
    }
    

    Call this method like so:

    [self sendLoginRequest:@"myUsername" password:@"password" callback:^(NSString *error, BOOL success) {
        if (success) {
             NSLog(@"My response back from the server after an unknown amount of time";
        }
    }
    

    See Apple's Programming with Objective-C for more reading on blocks and fuckingblocksyntax.com for how to declare blocks.