19

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;

}
pbaris
  • 4,525
  • 5
  • 37
  • 61
JayVDiyk
  • 4,277
  • 22
  • 70
  • 135
  • You can check `errorType` to know if there is an error. – Rajat Sep 15 '15 at 07:59
  • How can I know what errorType is it? – JayVDiyk Sep 15 '15 at 08:30
  • 1
    You should always check if the data is present or not, directly accessing this will crash in case it is nil. Never use forced unwrapping on optionals that need not be always non nil. – Shripada Sep 15 '15 at 08:34
  • 1
    As I wrote in the question, even if I check if data!= nil it always goes through that @Shripada – JayVDiyk Sep 15 '15 at 08:35
  • 1
    You should use Reachability to reliably check the connectivity-https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html – Shripada Sep 15 '15 at 08:38
  • refer to this question - http://stackoverflow.com/questions/28483577/ios-swift-how-to-manage-network-versatility-with-alamofire/37705432?noredirect=1#comment62889894_37705432 – Tushar Koul Jun 08 '16 at 16:37
  • Check this answer https://stackoverflow.com/a/71038385/3648678 – gyosida Feb 08 '22 at 17:42

7 Answers7

37

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

Andi
  • 8,154
  • 3
  • 30
  • 34
  • 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. – rocky raccoon May 30 '17 at 22:34
12

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
            }
    }
}
Melvin
  • 3,421
  • 2
  • 37
  • 41
5

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
}
ergoon
  • 1,264
  • 9
  • 17
  • I get "Use of unresolved identifiers 'getAuthenticationHeader' " – Luda Feb 10 '16 at 09:38
  • just remove this method call. it is specific to the question – ergoon Feb 11 '16 at 18:52
  • 1
    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. – HotFudgeSunday Dec 05 '17 at 16:08
5

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()
Avijit Nagare
  • 8,482
  • 7
  • 39
  • 68
SwiftStudier
  • 2,272
  • 5
  • 21
  • 43
4

Swift 5.0

You can check with NSURL-related Error Code

if error._code == NSURLErrorNotConnectedToInternet {
                        
}

Or you can check with the code

if error._code == -1009 {
                        
}

You can check other code on the developer site. https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes

Rashid Latif
  • 2,809
  • 22
  • 26
3

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)")
    }
}
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
2

It works in swift 5

.catchError { (error: Error) in
    if let err = error as? URLError, err.code  == URLError.Code.notConnectedToInternet {
        // No internet
    } else {
        // Other errors
    }
}
LinusGeffarth
  • 27,197
  • 29
  • 120
  • 174
NSnik
  • 51
  • 2