Home > Software engineering >  NSURLSessionDataTask wait completion failed
NSURLSessionDataTask wait completion failed

Time:06-27

I am passing a POST message using NSURLSessionDataTask in Objective-c.

The transfer task is non-blocking. I have to wait for the result so I use dispatch_semaphore_t to wait.

Unfortunately, when the corresponding function is called, the task does not work, why is that? The code below is shown.

NSString *urlString = [NSString stringWithFormat:@"http://localhost/api/test"];

char json_string[20] = "reqtestmsg";
size_t jsonLength = strlen(json_string);
NSData *jsonBodyData = [NSData dataWithBytes:json_string length:jsonLength];

NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = @"POST";

// for alternative 1:
[request setURL:[NSURL URLWithString:urlString]];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPBody:jsonBodyData];


NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                      delegate:nil
                                                 delegateQueue:[NSOperationQueue mainQueue]];
printf ("curl semaphore\n");

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

__block bool result = false;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                        completionHandler:^(NSData * _Nullable data,
                                                            NSURLResponse * _Nullable response,
                                                            NSError * _Nullable error) {


    NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
    NSLog(@"curl The response is: %@", asHTTPResponse);
    
    if (asHTTPResponse.statusCode == 200) {
        printf ("curl status 200 ok\n");
        result = true;
    }

    dispatch_semaphore_signal(semaphore);

}];

[task resume];
printf ("curl wait!!!");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // ==> blocked , task does not work!!!! 
printf ("curl wait!!! -1");

return result;

CodePudding user response:

You have specified your delegate queue to be the main queue. But you have blocked the main thread with dispatch_semaphore_wait. This is a classical deadlock, waiting for code to run on a queue which is blocked.

You could specify nil for your session’s delegate queue, and then you wouldn't deadlock. Or use [NSURLSession sharedSession].

I would also encourage you to consider eliminating the semaphores entirely. I understand the appeal of semaphores, but it is almost always the wrong solution. Apple removed synchronous networking API for a reason. The semaphore trick feels like an intuitive work-around, but it is inefficient, leads to substandard UX, and can even cause your app to be terminated by the watchdog process in certain situations.

  • Related