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.
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)
}