Best Approach For Checking Internet Connection in iOS

skJosh picture skJosh · Aug 2, 2016 · Viewed 17.1k times · Source

I have been searching through internet to find the best way to check for internet connection in iOS that works for both in IPv4 and IPv6 network environment. I found there are many possible answers but very confused on which one to apply. What I need to do is the following:

   // Check for internet connection

if (internetConnectionIsAvailable) {
   // make rest calls
}else
   // show cached data
}

I found the following options that are suggested in internet.

OPTION 1: Use apple Reachability class

With Reachability I can check internet connectivity as following which is short and direct, and don't have to wait for any response.

 - (BOOL)connected
    {
        Reachability *reachability = [Reachability reachabilityForInternetConnection];
        NetworkStatus networkStatus = [reachability currentReachabilityStatus];
        return !(networkStatus == NotReachable);
    }

- (void)viewDidLoad {
    [super viewDidLoad];

    if (![self connected]){
     // Not connected
    }else{
    // Connected
    }

}

But here internet checking is done at pre-flight, which is against suggestion by apple engineer as seen on WWDC video. Also if you check ReadMe.md, it has been mentioned that Reachability fully supports IPv6. But if method reachabilityForInternetConnection is checked in Reachability.m they have used sockaddr_in, sockaddr_in6 has not been used which is recommended for IPv6 network. So I don't know if it will work in IPv6 network.

OPTION 2: Use Alamofire to connect

  • Just try to connect as in one of stackoverflow answer. The code also shown below:-

    Alamofire.request(.GET,"http://superrandomdomainnamethatisnotused.com/superrandompath").responseString {
        (request, response, stringData, error) in
    
        if let networkError = error {
            if (networkError.code == -1009) {
                println("No Internet \(error)")
            }
        }
    }
    

But isn't it time consuming to try to connect to some host, wait for the response and then know if online/offline.

OPTION 3: Use Tony Million's version of Reachability. But the author has warned of app being rejected while using this. I can use this as code shown below:-

// Checks if we have an internet connection or not
- (void)testInternetConnection
{   
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"There in internet connection");
        });
    };

    // Internet is not reachable
    internetReachableFoo.unreachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Someone broke the internet :(");
        });
    };

    [internetReachableFoo startNotifier];
}

But in this option, my question is, is this right approach to test internet by connecting http://google.com . Does this guarantee 100% results? What if google is down? If the app is used in country where google.com is not allowed whats the result?

So I have been in a big dilemma which option to choose, if these options are the right way or is there a better way of checking internet which guarantee 100% results and works in both IPv4 and IPv6 network. Can anyone suggest me which option is better or should I go for other approach, what is the better way to accomplish this.

Your reply will be much appreciated.

Answer

emraz picture emraz · Sep 20, 2016

For Swift 3, Xcode 8......

func isInternetAvailable() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
    zeroAddress.sin_family = sa_family_t(AF_INET)

    guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
    }) else {
        return false
    }

    var flags: SCNetworkReachabilityFlags = []
    if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
        return false
    }

    let isReachable = flags.contains(.reachable)
    let needsConnection = flags.contains(.connectionRequired)

    return (isReachable && !needsConnection)
}