Carpetfizz
Carpetfizz

Reputation: 9149

NSURLConnection async not working

I'm trying to make an asynchronous NSURL Request, but I'm getting all "FALSE."

-(BOOL)checkConnectionForHost:(NSString*)host{

   BOOL __block isOnline = NO;
   NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:host] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:1];
   [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
      if([(NSHTTPURLResponse*)response statusCode]==200){
         isOnline = TRUE;
      }
   }];
   NSLog(@"%i",isOnline);
   return isOnline;
}

Also, this code is being called "6" times when I'm actually just using it with a:

-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

and there are only 3 cells, or 3 items in my data source. First time dealing with async and callbacks in Objective-C, so a detailed answer would be much appreciated! Thanks!

Upvotes: 0

Views: 416

Answers (3)

CouchDeveloper
CouchDeveloper

Reputation: 19098

You should realize that this problem is inherently asynchronous. You can't solve it with a synchronous approach. That is, your accepted solution is just an elaborated and suboptimal wrapper which ends up being eventually asynchronous anyway.

The better approach is to use an asynchronous method with a completion handler, e.g.:

typedef void (^completion_t)(BOOL isReachable);

-(void)checkConnectionForHost:(NSString*)host completion:(completion_t)completionHandler;

You can implement is as follows (even though the request isn't optimal for checking reachability):

-(void)checkConnectionForHost:(NSString*)host 
                   completion:(completion_t)completionHandler 
{
   NSURLRequest* request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:host]];
   [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
      if (completionHandler) {
          completionHandler(connectionError == nil && [(NSHTTPURLResponse*)response statusCode]==200);
      }
   }];
}

Please note:

  • Don't set a timeout as short as in your original code.
  • The completion handler will be called on a private thread.

Usage:

[self checkConnectionForHost:self.host completion:^(BOOL isReachable){
    dispatch_async(dispatch_get_main_queue(), ^{
        self.reachableLabel.text = isReachable ? @"" : @"Service unavailable";
    });    
}];

Upvotes: 2

Bilal Saifudeen
Bilal Saifudeen

Reputation: 1677

Asynchronous calls will be executed in parallel, and its result will receive in the completion block. In your case, the return statement will be executed before the completion of the Asynchronous request. That will be always FALSE.

You should use Synchronous request for this, and handle not to Block the UI.

-(BOOL)checkConnectionForHost:(NSString*)host{

    BOOL isOnline = NO;
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:host] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:1];
    NSHTTPURLResponse *response;
    NSError *error;

    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

    NSLog(@"Response status Code : %d",response.statusCode);
    isOnline = response.statusCode == 200;

    return isOnline;    
}

You can use that method inside dispatch queues,

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
    BOOL status = [self checkConnectionForHost:@"http://google.com"];
    NSLog(@"Host status : %@",status ? @"Online" : @"Offline");
});

Upvotes: 5

erikprice
erikprice

Reputation: 6308

Your isOnline is probably being set to YES, but it's happening asynchronously. It is almost certainly executing after you log out the value of isOnline. So you should move your NSLog() call up into the block you pass as the handler to the asynchronous URL request.

Upvotes: 1

Related Questions