Handle No Internet Connection Error Before Try to Parse the Result in Alamofire

27,923

Solution 1

I agree with @Shripada. First you should use Reachability to check for connectivity. There is a Swift library here: https://github.com/ashleymills/Reachability.swift

additionally you can use one of the Alamofire validation methods:

Alamofire.request(.POST, REGISTER_URL, parameters: parameters, encoding: .JSON, headers: getAuthenticationHeader()).validate(statusCode: 200 ..< 300).response { (request, response, data, error) -> Void in
    if error != nil {
        println("Server responded with: \(response.statusCode)")
        return
    }

    // Handle your response data here
}

Solution 2

Swift 3 Solution

Assuming you have an Error instance you can do the following:

if let err = error as? URLError, err.code  == URLError.Code.notConnectedToInternet
{
    // No internet
}
else
{
    // Other errors
}

You simply cast error into a URLError. This works since URLError implements the Error protocol. Here is a quote from the apple documentation for reference:

URLError: Describes errors in the URL error domain.

Once you have a URLError instance you can simply compare its code property, which is a URLError.Code enum, against the any relevant enum cases (in our example URLError.Code.notConnectedToInternet).

Solution 3

This works for me in 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
            }
    }
}

Solution 4

Other way to check for internet connection existing

import SystemConfiguration

func connectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in()    

       zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))

        zeroAddress.sin_family = sa_family_t(AF_INET)

      guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else {
            return false
        }
        var flags : SCNetworkReachabilityFlags = []

        if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {

            return false

        }

        let isReachable = flags.contains(.Reachable)

        let needsConnection = flags.contains(.ConnectionRequired)

        return (isReachable && !needsConnection)

    }

let hasInternet = connectedToNetwork()

Solution 5

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Prepare

Edit NSAppTransportSecurity in Info.plist:

Code:

<key>NSAppTransportSecurity</key>
    <dict>
    <key>NSAllowsArbitraryLoads</key><true/>
</dict>

Sample 1 (need Alamofire pod)

Use Network Reachability

import UIKit
import Alamofire

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: .init(x: 80, y: 80, width: 100, height: 40))
        button.setTitle("Check", for: .normal)
        button.addTarget(self, action: #selector(checkInternetConnection), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
    }

    @objc func checkInternetConnection() {
        guard let networkReachabilityManager = NetworkReachabilityManager(host: "http://google.com") else { return }
        networkReachabilityManager.listener = { [weak self] status in
            let alert = UIAlertController(title: "Network Status ", message: "\(status)", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] _ in
                alert?.dismiss(animated: true, completion: nil)
            }))
            self?.present(alert, animated: true, completion: nil)
        }
        networkReachabilityManager.startListening()
    }
}

Sample 2 (need Alamofire pod)

import UIKit
import Alamofire

class ViewController: UIViewController {

    private lazy var networkManager = NetworkManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: .init(x: 80, y: 80, width: 100, height: 40))
        button.setTitle("Check", for: .normal)
        button.addTarget(self, action: #selector(checkInternetConnection), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
    }

    @objc func checkInternetConnection() {
        let urlString = "http://dummy.restapiexample.com/api/v1/employees"
        networkManager.sessionManager.request(urlString).validate().response { response in
            print("\(response.data as Any)")
        }
    }
}


class NetworkManager {
    lazy var sessionManager: SessionManager = {
        let configuration = URLSessionConfiguration.default
        configuration.httpCookieStorage = nil
        configuration.httpCookieAcceptPolicy = HTTPCookie.AcceptPolicy.never
        let manager = SessionManager(configuration: configuration)
        manager.retrier = self
        return manager
    }()
}

extension NetworkManager: RequestRetrier {
    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
        let error = error as NSError
        switch error.code {
            case -1009:
                DispatchQueue.main.async {
                    let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] _ in
                        alert?.dismiss(animated: true, completion: nil)
                    }))
                    UIApplication.topMostViewController?.present(alert, animated: true, completion: nil)
                }
            default: break
        }
        print("-- Error code: \(error.code)")
        print("-- Error descriptiom: \(error.localizedDescription)")
    }
}


// https://stackoverflow.com/a/52932487
extension UIViewController {
    var topMostViewController: UIViewController {

        if let presented = self.presentedViewController {
            return presented.topMostViewController
        }

        if let navigation = self as? UINavigationController {
            return navigation.visibleViewController?.topMostViewController ?? navigation
        }

        if let tab = self as? UITabBarController {
            return tab.selectedViewController?.topMostViewController ?? tab
        }
        return self
    }
}

extension UIApplication {
    class var topMostViewController : UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController?.topMostViewController
    }
}

Sample 3 (without third party library)

More info: How to use SCNetworkReachability in Swift

import UIKit
import SystemConfiguration

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: .init(x: 80, y: 80, width: 100, height: 40))
        button.setTitle("Check", for: .normal)
        button.addTarget(self, action: #selector(checkInternetConnection), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
    }

    @objc func checkInternetConnection() {
        print("-- \(URLSession.connectedToNetwork())")
    }
}

extension URLSession {
    class func connectedToNetwork() -> Bool {
        var zeroAddress = sockaddr()
        zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
        zeroAddress.sa_family = sa_family_t(AF_INET)
        guard let networkReachability = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return false }
        var flags = SCNetworkReachabilityFlags()
        SCNetworkReachabilitySetDispatchQueue(networkReachability, DispatchQueue.global(qos: .default))
        if SCNetworkReachabilityGetFlags(networkReachability, &flags) == false { return false }
        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)
        return isReachable && !needsConnection
    }
}

Sample 4 (need Reachability.swift pod)

import UIKit
import Reachability

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(frame: .init(x: 80, y: 80, width: 100, height: 40))
        button.setTitle("Check", for: .normal)
        button.addTarget(self, action: #selector(checkInternetConnection), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
    }

    @objc func checkInternetConnection() {
        guard let reachability = Reachability(hostname: "google.com", queueQoS: .utility) else { return }
        try? reachability.startNotifier()
        print("-- \(reachability.connection as Any)")
    }
}
Share:
27,923
JayVDiyk
Author by

JayVDiyk

Updated on July 25, 2022

Comments

  • JayVDiyk
    JayVDiyk almost 2 years

    How should I handle if there is an error occurs when there is no internet connection in Alamofire. I tried checking if data is nil or not but it does not work.

    Below is how I use Alamofire

    Alamofire.request(.POST, REGISTER_URL, parameters: parameters, encoding: .JSON, headers: getAuthenticationHeader()).response { (request, response, data, errorType) -> Void in
    
        let resultObject: APIResults = APIResults(JSONDecoder(data!));
        let responseCode: Int = Int(resultObject.code!)!;// THIS CRASHES WHEN THERE IS NO INTERNET CONNECTION
    
        if (responseCode == 200) {
            available = true;
        }
    
        finished = true;
    
    }
    
  • Luda
    Luda about 8 years
    I get "Use of unresolved identifiers 'getAuthenticationHeader' "
  • ergoon
    ergoon about 8 years
    just remove this method call. it is specific to the question
  • rocky raccoon
    rocky raccoon almost 7 years
    Sometimes, Alamofire returns Error without any sort of error code after it. This happens only when I'm not running localhost. I forgot the error code, but it had to do with not connecting to a server even though the internet was on and I want to be able to catch that.
  • HotFudgeSunday
    HotFudgeSunday over 6 years
    Reachability is a problem you don't need unless your App needs to be constantly connected, for whatever reason. I generally don't need it. Users only need connectivity when they're requesting data, the rest of the time they can use cached data in most Apps.