9

I just need to check the internet connection availability before start communicating with the service in my iphone App. I am using Swift 1.2 and Xcode 6 as my development environment...

I've just done some research and found this stackoverflow LINK in objective C.

Therefore I just tried to find a similar solution in SWIFT and found the following link

https://coderwall.com/p/mhxbpq/checking-for-internet-connection-availability

Just to make things easy the content in that link is as follows...

import Foundation
import SystemConfiguration

public class Reachability {

  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) ? true : false
  }

}

And check the connection availability like this...

if Reachability.isConnectedToNetwork() 
{
    println("Haz Interwebz!")
}  
else
{
    println("Oh noes! No interwebz!!!")
}

NOTE: To work this needs to add SystemConfiguration.framework to the project (For "Linked Frameworks and Libraries")....

So.... My question is, I am quite new for iOS development and NOT quite sure how good and relaible it is to use this logic to get it done. Most of the stuff in that class are completely not clear, but the small tests I've done works good!!!

Like to hear what more experiance ios developers have to say about this.

Community
  • 1
  • 1
JibW
  • 4,347
  • 14
  • 61
  • 100

4 Answers4

12

I was looking to solve the same problem for myself this morning and I felt that this "Reachability" sample code provided from Apple does not appeal to me at all (mostly because of the manual opening of sockets and the SystemConfiguration ugly API).

Instead of this I tried to make a simple HTTP connection to a random non-existing URL using Alamofire (I already had it as a dependency) and check the value in the error that I would receive.

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

This code could be rewritten using any other networking library. Error -1009 is corresponding to NSURLErrorNotConnectedToInternet which is somewhat more reassuring way of saying "you are really not connected to the Internet".

Another good thing is that this works even if you put non-existing URL, which means that you don't have to make a successful HTTP request to any server even if you have Internet connection.

The downside is that the code in the block is executed asynchronously, which could be inconvenience depending on your requirements.

Lachezar
  • 5,967
  • 2
  • 30
  • 34
  • This may be out of date. I would not recommend to use a get api for network reachability. See my [answer](https://stackoverflow.com/a/49615304/2581637) below. – nuynait Apr 02 '18 at 16:54
5

An improved version of @Lachezar's answer for Swift2.x:

Alamofire.request(.POST, url).responseJSON { response in
    switch response.result {
        case .Success(let json):
            // internet works.  
        case .Failure(let error):

            if let err = error as? NSURLError where err == .NotConnectedToInternet {
                // no internet connection
            } else {
                // other failures
            }
    }
}

If you would like the network status without parsing an URL, I suggest this solution: https://stackoverflow.com/a/38646078/706933

Community
  • 1
  • 1
Melvin
  • 3,352
  • 2
  • 33
  • 40
2

Edit for Swift 5.x :

import SystemConfiguration

public class CheckInternet{

    class func Connection() -> 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(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
                SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
            }
        }

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


        // Working for Cellular and WIFI
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        let ret = (isReachable && !needsConnection)

        return ret


    }

}
Thomas
  • 295
  • 2
  • 15
0

Alamofire

I would recommend listen to reachability instead of using a get api.

You can add following class to your app, and call MNNetworkUtils.main.isConnected() to get a boolean on whether its connected or not.

class MNNetworkUtils {
  static let main = MNNetworkUtils()
  init() {
    manager = NetworkReachabilityManager(host: "google.com")
    listenForReachability()
  }

  private let manager: NetworkReachabilityManager?
  private var reachable: Bool = false
  private func listenForReachability() {
    self.manager?.listener = { [unowned self] status in
      switch status {
      case .notReachable:
        self.reachable = false
      case .reachable(_), .unknown:
        self.reachable = true
      }
    }
    self.manager?.startListening()
  }

  func isConnected() -> Bool {
    return reachable
  }
}

This is a singleton class. Every time, when user connect or disconnect the network, it will override self.reachable to true/false correctly, because we start listening for the NetworkReachabilityManager on singleton initialization.

Also in order to monitor reachability, you need to provide a host, currently I am using google.com feel free to change to any other hosts or one of yours if needed.

nuynait
  • 1,752
  • 17
  • 26
  • Why do you use [unowned self] ? It crashes when it tries to acces self.reachable "object was already deallocated" – Nathan Barreto Jul 10 '18 at 18:59
  • 1
    @NathanMartins To avoid the retain cycle by passing in a weak reference. Are you using the extension as is? The network utility class is a singleton which should always exists inside memory. This is strange to get "object was already deallocated". You can change unowned self to weak self, If self is nil, return to avoid the crash. – nuynait Jul 12 '18 at 04:25