36

I am trying to determine if the user is connected to the internet by using AFNetworking 2.0 and the "AFNetworkReachabilityManager", but it doesen't seem to work. It's always return that there is a valid internet connection, even though the internet is turned off. This is my code:

 -(BOOL)connected {

   __block BOOL reachable;

    [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

        switch (status) {
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"No Internet Connection");
                reachable = NO;
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WIFI");

                reachable = YES;
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"3G");
                reachable = YES;
                break;
            default:
                NSLog(@"Unkown network status");
                reachable = NO;
                break;

                [[AFNetworkReachabilityManager sharedManager] startMonitoring];
        }
    }];

    return reachable;

}

This method is called from my viewDidLoad method. Is there something wrong with my code, since it isn't working?

7 Answers7

101

You're making this more difficult than it needs to be. Try this:

- (void)viewDidLoad {
   [super viewDidLoad];

   [[AFNetworkReachabilityManager sharedManager] startMonitoring];

}

- (BOOL)connected {
    return [AFNetworkReachabilityManager sharedManager].reachable;
}   

If you also want to be notified when the status changes, then implement setReachabilityStatusChangeBlock.

starball
  • 20,030
  • 7
  • 43
  • 238
backofthecup
  • 1,091
  • 2
  • 6
  • 7
  • This works perfect. I didn't need to `#import ` in my .pch file. Remember to test this on an actual device, because in the iOS simulator it seems like it always returns `true`. – Alex Jun 23 '14 at 18:50
  • 6
    The simulator just returns your computer's status. Try disconnecting the network and you'll see. – mikker Jun 27 '14 at 11:43
  • @mikker The problem is that cutting the wifi on your mac later doesn't seem to trigger the status change block. It only works for the initial check. – user3344977 Jan 06 '21 at 18:28
64

That's because that block is only executed when reachability changes.

To get the current status, you can do this:

- (BOOL)connected {
    return [AFNetworkReachabilityManager sharedManager].reachable;
}
Marcelo
  • 9,916
  • 3
  • 43
  • 52
  • 2
    Thank you for your answer. It doesn't seem to work though, it always returns NO (not connected), even though WIFI and 3G is turned on/off. Any idea why this happens? – 7c9d6b001a87e497d6b96fbd4c6fdf Nov 04 '13 at 20:18
  • 1
    This is the current status. Maybe you want to listen to `AFNetworkingReachabilityDidChangeNotification` or use the `reachabilityStatusChangeBlock` to get updates. – Marcelo Nov 04 '13 at 23:54
  • 6
    Are you running on an actual device, or in the simulator? The simulator doesn't always know what it's network availability is. – Johanneke May 21 '14 at 12:43
  • Take a look at the answer below. You should startMonitoring in viewDidLoad and give it a little bit to check the connectivity – anders Sep 11 '14 at 15:46
  • this is always returning FALSE :( – Chetan Prajapati Sep 29 '15 at 12:30
  • People saying this is not working have a look at this answer http://stackoverflow.com/a/35497418/1679519 – Bernard Feb 19 '16 at 04:38
11

You have two code errors that will prevent your code from working.

First, your call to 'start monitoring' occurs inside the block that is fired in response to reachability changes -- therefore, the block will never fire (unless you start monitoring elsewhere).

Second, there are no guarantees on when that block will fire. As a result, you'll always see 'reachable' return whatever value it was initialized to -- apparently this is usually null. Even if you fix the first error, there's no guarantee (and it's actually rather unlikely) that the block will fire before you return.

Finally, on a more general level, you're also trying to test in a synchronous manner code that can only be executed asynchronously. Which is to say, it's impossible for the reachability manager to accurately determine reachability instantaneously. It can say 'I think I'm on WiFi' or 'I think I'm on 3G', but it also needs to check to see if it can actually reach the internet (hence the name reachability) before it can be certain. Reachability isn't just about 'I have a wifi' or 'I have a 3g' connection, it's also about whether you can reach the internet through it. This means the device actually has to send a request, and while this can, technically, be done in a synchronous manner, every single rule in the book insists that network code must be done asynchronously, and for good reason. If you did is synchronously, you'd block your UI until the network call returns... possibly a good 30, 40, 50, even 60 seconds later, depending on the relevant timeouts.

What you should do is start the reachability singleton monitoring in your app did load method of the app delegate, then retrieve it's data later. Without knowing the structure of your app I won't even try to guarantee accuracy, but that should at least help, somewhat.

RonLugge
  • 5,086
  • 5
  • 33
  • 61
7

Try this,

In AppDelegate, didFinishLaunchingWithOptions method

{ // SETUP AFNETWORKING's NETWORK INDICATOR AND REACHABILITY
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    [[AFNetworkReachabilityManager sharedManager] startMonitoring];
}

In HttpManager class,

- (BOOL)isNetworkRechable {

    if ([AFNetworkReachabilityManager sharedManager].reachable) {

        if ([AFNetworkReachabilityManager sharedManager].isReachableViaWiFi)
            NSLog(@"Network reachable via WWAN");
        else
            NSLog(@"Network reachable via Wifi");

        return YES;
    }
    else {

        NSLog(@"Network is not reachable");
        return NO;
    }
}

In yourViewController,

[[HttpManager sharedObject] isNetworkRechable];

Note: Don't check networkRechability at very first. Because it will not work. So please wait minimum 1 sec to check it.

Balaji G
  • 121
  • 2
  • 3
6

As per my experience,

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

takes a moment to execute setReachabilityStatusChangeBlock so there is no use returning value from -(BOOL)connected.

So you can perform some task once network is connected/disconnected.

The following function is best to check connectivity at the spot (synchronously):

[AFNetworkReachabilityManager sharedManager].reachable;
Steph Sharp
  • 11,462
  • 5
  • 44
  • 81
For Guru
  • 1,197
  • 13
  • 23
3

The other answers are wrong! It's better to use this to check availabilty:

if ([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable)

The reason why is because initially networkReachabilityStatus will be set to AFNetworkReachabilityStatusUnknown until the change status block is called and this stops your code from thinking that network is unavailable when it is not.

1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    [self checkNetworkReachability];
}    


+(BOOL) isReachable{
   return [AFNetworkReachabilityManager sharedManager].reachable;
}

+(void) checkNetworkReachability{
        [[AFNetworkReachabilityManager sharedManager] startMonitoring];
        [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));

            // Check the reachability status and show an alert if the internet connection is not available
            switch (status) {
                case -1:
                    // AFNetworkReachabilityStatusUnknown = -1,
                    NSLog(@"The reachability status is Unknown");
                    break;
                case 0:
                    // AFNetworkReachabilityStatusNotReachable = 0
                    NSLog(@"The reachability status is not reachable");
                    break;
                case 1:
                    NSLog(@"The reachability status is reachable via wan");
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"Network_Reachable" object:nil];
                    break;
                case 2:
                    // AFNetworkReachabilityStatusReachableViaWiFi = 2
                    NSLog(@"The reachability status is reachable via WiFi");

                    [[NSNotificationCenter defaultCenter] postNotificationName:@"Network_Reachable" object:nil];
                    break;

                default:
                    break;
            }

        }];
    }
Bassant Ashraf
  • 1,531
  • 2
  • 16
  • 23