user-44651
user-44651

Reputation: 4124

NSHTTPURLResponse is nil but no NSError is generated

I am trying to read the NSHTTPURLResponse status code, however the NSHTTPURLResponse is returning nil, but no NSError is created.

This worked prior to iOS 11, but I am getting no warnings that it is deprecated and I am unable to find anything online referencing NSURLSession with this issue.

Any idea why?

I generally call the below method [MyClass getHTTPResponseRequest:@"http://www.google.com/"];

+ (NSInteger) getHTTPResponseRequest : (NSString*) testURL {
    __block NSHTTPURLResponse * r = nil;

    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:testURL]
                                 completionHandler:^(NSData *data, NSURLResponse *response,  NSError *error) {

                if (error) {
                     NSLog(@"Error %@", error.localizedDescription);
                }

                r = (NSHTTPURLResponse *)response;

    }] resume];

    if(r == nil){
        NSLog(@"Response is nil");
        return 9999;
    }

    return r.statusCode;
}

Upvotes: 1

Views: 637

Answers (1)

Rob
Rob

Reputation: 438202

This would not have worked prior to iOS 11 either. The dataTaskWithURL completion handler is called asynchronously, but you're not waiting for the request to finish before attempting to return the statusCode.

You should adopt an asynchronous pattern, e.g. use completion handler pattern yourself:

+ (void)getHTTPResponseRequestWithURL:(NSString *)urlString completion:(void(^ _Nonnull)(NSInteger))completion {
    NSURL *url = [NSURL URLWithString:urlString];

    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response,  NSError *error) {
        if (error) {
            NSLog(@"Error %@", error.localizedDescription);
        }

        NSInteger statusCode;
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            statusCode = [(NSHTTPURLResponse *)response statusCode];
        } else {
            statusCode = 9999;
        }

        completion(statusCode);
    }] resume];
}

And you'd call it like:

[MyClass getHTTPResponseRequestWithURL:@"http://google.com" completion:^(NSInteger statusCode) {
    // examine the `statusCode` here

    NSLog(@"%ld", (long)statusCode);
}];

// but the above runs asynchronously, so you won't have `statusCode` here

Now, clearly your completion handler parameters are generally returning something more meaningful than just the integer statusCode, but it illustrates the idea: Don't try to return a value from an asynchronous method without employing an asynchronous pattern (such as the completion handler).

Upvotes: 1

Related Questions