18

How can I check network status in Swift? In Objective-C Reachability.h .m files were available. What now? How can I check whether I am online or offline?

János
  • 32,867
  • 38
  • 193
  • 353
  • you don't need to check whether the network is available, it is good enough if you start the request and handle the possible error properly. – holex Jul 01 '14 at 18:24
  • 2
    yes, but if only 3G is available then check will cost money, in case of a business app, nobody wants to pay for this – János Jul 01 '14 at 18:27
  • If there is no connection, there is no outgoing/incoming data, therefore it will cost nothing. – holex Jul 01 '14 at 18:40
  • @holex there are many good reasons to check reachability to either specific sites or the network in general before attempting transfers. – David Berry Jul 01 '14 at 18:54
  • @holex from O'Reilly, Learning iOS: "One of the more common reasons for Apple to reject an application submitted for review is that the application doesn’t correctly notify the user when the application fails to access the network. Apple requires that you detect the state of the network connection and report it to the user when the connection is unavailable" – David Oct 31 '14 at 09:46
  • 1
    @David, I agree with you, and the Apple is damn right in this! the end-user has to be informed properly, however, the Apple's reachability is just _one_ of the many options which you could use to detect the network's status, not the _only_ option – it is not mandatory to use, but _notifying the end-user_ is. on other hands during one of the WWDCs the Apple directly encourage the developer no to use the reachability, but make the request directly and handle the _completion_ and _failure_ scenarios, that is more then enough for them, but the developers do not do such easy thing either... :( – holex Oct 31 '14 at 14:04
  • @holex which WWDC video was it do you remember? – bandejapaisa Nov 23 '14 at 23:19
  • @bandejapaisa, it was a WWDC about 3 years ago, I don't recall whether it was Job's last WWDC or happened after. – holex Nov 23 '14 at 23:40
  • 1
    @bandejapaisa seems like this one: https://developer.apple.com/videos/play/wwdc2012/706/ – wzso Oct 12 '17 at 13:06

7 Answers7

14

If you're looking for a Swift implementation of Apple's Reachability class, you could take a look at this:

http://github.com/ashleymills/Reachability.swift

It's a drop in class, using notifications and closures.

Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
11

You can still use Reachability in Swift. Logan has a good answer on how to add objective-c files to a bridging header here. Once you have your bridging header set up, you can call the Reachability methods from your Swift code. Something like this would work:

class func hasConnectivity() -> Bool {
    let reachability: Reachability = Reachability.reachabilityForInternetConnection()
    let networkStatus: Int = reachability.currentReachabilityStatus().value
    return networkStatus != 0
}
Community
  • 1
  • 1
Connor Pearson
  • 63,902
  • 28
  • 145
  • 142
  • huh, mix Objective-C and Swift, isn't it out a better idea? – János Jul 01 '14 at 18:23
  • Well all of Apple's frameworks (Cocoa, Foundation, CFNetwork etc..) are all Objective-c frameworks, so for a while at least if you want to do anything it will use objective-c in some way. – Connor Pearson Jul 01 '14 at 18:27
  • 3
    @connor note that the Reachability foundation routines are all asynchronous, so just immediately querying currentReachabilityStatus isn't useful. In general you're correct that Reachability can be bridged using the bridging headers, once that's done, following any Reachability tutorial will work with appropriate translations. – David Berry Jul 01 '14 at 18:52
  • thanks for the info @David. I actually haven't used Reachability myself – Connor Pearson Jul 01 '14 at 19:05
  • 3
    Its better to not compare to `0` but to `NotReachable.value`. Easier to read in the future. – Paul Peelen Aug 01 '15 at 22:02
7

i will give best solution, hope its helpful.

import Foundation
import SystemConfiguration

public class Reachability {
    class func isConnectedToNetwork()->Bool{

        var Status:Bool = false
        let url = NSURL(string: "http://google.com/")
        let request = NSMutableURLRequest(URL: url!)
        request.HTTPMethod = "HEAD"
        request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
        request.timeoutInterval = 10.0

        var response: NSURLResponse?

        var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData?

        if let httpResponse = response as? NSHTTPURLResponse {
            if httpResponse.statusCode == 200 {
                Status = true
            }

        }
        else
        {

            let alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
            alert.show()
        }

        return Status
    }
}

How to access or call in other classes:

 if Reachability.isConnectedToNetwork() == true {

// write your code

}
Natalia
  • 1,308
  • 16
  • 23
Ishwar Hingu
  • 562
  • 7
  • 14
  • 1
    This is a good answer, but it will fail in China and other countries where google.com is blocked. I have posted an adjusted version below. – blwinters Jul 29 '15 at 18:43
  • 1
    Please don't use this. For users with slow internet connections and connected to cellular data like 2G/GPRS, this method may not work! – Axe Jul 14 '16 at 15:59
4

First add Reachability.swift file into your project that you can get from here below link

https://github.com/pavangandhi/TestProject/tree/master/TestProject/AppConstants

Use the below given code to test app is connected with internet or not :

// check internet connectivity if its returns YES means its connect with internet, Wifi and cellular data

class func isConnectedToNetwork() -> Bool 
{
    let reachability = Reachability.reachabilityForInternetConnection()

    if reachability.isReachable() || reachability.isReachableViaWiFi() || reachability.isReachableViaWWAN()
    {
        return true
    }
    else
    {
        return false
    }
}

Note : You need to add Reachability.swift file into your project before adding this code.

Lotus Shah
  • 493
  • 4
  • 13
3

I've been using the code from this article successfully. Though after releasing my app I realized that google.com is blocked in China and this code is flawed in countries where Google is blocked. So I adjusted it to check a second URL if the first one fails. If the second one succeeds, then I save it as the preferred URL.

Edit: While the following code is still valid, after using it in the wild I noticed that testing the network by loading a URL can cause unacceptable delays when the user is connected to a weak (non-4G) cellular data connection. I now use the Reachability class as suggested by @Ashley Mills above.

public class Network {

class func isConnectedToNetwork() -> Bool{
    let defaults = NSUserDefaults.standardUserDefaults()

    var networkStatus:Bool = false
    let urlA = NSURL(string: "http://google.com/")
    let urlB = NSURL(string: "http://baidu.com/")

    let urlDict:[String:NSURL] = ["A":urlA!, "B":urlB!]

    var preference = "A"

    if let temp = defaults.stringForKey("preferredNetworkURL") {
        preference = temp //check the last successful URL or A by default
    } else {
        defaults.setObject(preference, forKey: "preferredNetworkURL")
    }

    networkStatus = Network.fetchURL(urlDict[preference]!, pref:preference)

    if networkStatus == false {
        //check the URL which hasn't been checked
        if preference == "A" {
            preference = "B"
        } else {
            preference = "A"
        }
        networkStatus = Network.fetchURL(urlDict[preference]!, pref:preference)
        println("NETWORK STATUS: \(networkStatus)")
        //if preference "B" returns true, then Baidu.com is available and user is likely in a country where Google is blocked
    }

    return networkStatus
}

class func fetchURL(url:NSURL, pref:String) -> Bool {
    println("URL PREFERENCE: \(pref)")
    let defaults = NSUserDefaults.standardUserDefaults()
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "HEAD"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
    request.timeoutInterval = 10.0

    var response: NSURLResponse?

    var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData?

    if let httpResponse = response as? NSHTTPURLResponse {
        if httpResponse.statusCode == 200 {
            defaults.setObject(pref, forKey: "preferredNetworkURL") //remember the URL that succeeded and check it first next time
            return true
        } else {
            return false
        }
    } else {
        return false
    }
}

}

Then anywhere I need to check for a network connection I call:

if Network.isConnectedToNetwork() == true {
    //perform network dependent actions
} else {
    var alert = UIAlertView(title: "Network Unavailable", message: "Please connect to the internet in order to proceed.", delegate: self, cancelButtonTitle: "OK")
    alert.show()
}
blwinters
  • 1,911
  • 19
  • 40
  • maybe the down voter think your preferred url is not essential. What a pity. – HamasN Aug 08 '15 at 13:26
  • This was easy to install and i like the alertview setup. Unfortunately I realize it seems to only give me isConnectedToNetwork() == false, even when i have double checked that i have internet and can successfully use internet based features in other apps. Any idea why it would behave this way? – Natalia Feb 28 '16 at 06:37
0

Checking the Internet connection availability in (iOS) Xcode 7.2 , Swift 2.0

This is simple method for checking the network availability. I managed to translate it to Swift 2.0 and here the final code. The existing Apple Reachability class and other third party libraries seemed to be too complicated to translate to Swift. This works for both 3G and WiFi connections. Don’t forget to add “SystemConfiguration.framework” to your network.

 //Create new swift class file Reachability in your project.

 import SystemConfiguration


 public class InternetReachability {

  class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
       zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
       zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
              SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)).takeRetainedValue()
        }

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

       let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
       let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0

       return isReachable && !needsConnection
  }

  }

// Check network connectivity from anywhere in project by using this code.

   if InternetReachability.isConnectedToNetwork() == true {
          print("Internet connection OK")
    } else {
         print("Internet connection FAILED")
  }
ViJay Avhad
  • 2,684
  • 22
  • 26
0

@blwinters I rewrote this code to work with closures and work in the latest version of swift.

import AVFoundation
public class Network {

    class func isConnectedToNetwork(resultHandler: (isTrue: Bool) -> Void) {
        let defaults = NSUserDefaults.standardUserDefaults()

        let urlA = NSURL(string: "http://google.com/")
        let urlB = NSURL(string: "http://baidu.com/")

        let urlDict:[String:NSURL] = ["A":urlA!, "B":urlB!]

        var preference = "A"

        if let temp = defaults.stringForKey("preferredNetworkURL") {
            preference = temp //check the last successful URL or A by default
        } else {
            defaults.setObject(preference, forKey: "preferredNetworkURL")
        }

        Network.fetchURL(urlDict[preference]!, pref:preference) {
            isTrue in
            if isTrue == true {
                print("NETWORK STATUS: \(isTrue)")
                resultHandler(isTrue: isTrue)
            } else {
                //check the URL which hasn't been checked
                if preference == "A" {
                    preference = "B"
                } else {
                    preference = "A"
                }
                Network.fetchURL(urlDict[preference]!, pref:preference) {
                    isTrue in
                    print("NETWORK STATUS: \(isTrue)")
                    resultHandler(isTrue: isTrue)
                }
                //if preference "B" returns true, then Baidu.com is available and user is likely in a country where Google is blocked
            }
        }
    }

    class func fetchURL(url:NSURL, pref:String, resultHandler: (isTrue: Bool) -> Void) {
        print("URL PREFERENCE: \(pref)")
        let defaults = NSUserDefaults.standardUserDefaults()
        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "HEAD"
        request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
        request.timeoutInterval = 10.0

        var returnBool = false
        let session = NSURLSession(configuration: .defaultSessionConfiguration())
        let dataTask = session.dataTaskWithRequest(request) {
            (let data, let response, let error) in
            if let httpResponse = response as? NSHTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    defaults.setObject(pref, forKey: "preferredNetworkURL") //remember the URL that succeeded and check it first next time
                    returnBool = true
                    resultHandler(isTrue: returnBool)
                } else {
                    returnBool = false
                    resultHandler(isTrue: returnBool)
                }
            } else {
                returnBool = false
                resultHandler(isTrue: returnBool)
            }
        }
        dataTask.resume()
    }
}

Then you use it like so

    Network.isConnectedToNetwork(){
        isConnected in
        if isConnected == true {
            dispatch_async(dispatch_get_main_queue()) {
                    //perform network dependent actions
                    //can remove the dispatch async if non UI actions
            }
        } else {
            dispatch_async(dispatch_get_main_queue()) {
                let alertController = UIAlertController(title: "Network Unavailable", message: "Please connect to the internet in order to proceed.", preferredStyle: UIAlertControllerStyle.Alert)
                alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default,handler: nil))
                self.presentViewController(alertController, animated: true, completion: nil)
            }
        }
    }
Sethmr
  • 3,046
  • 1
  • 24
  • 42