ios 在尝试解析 Alamofire 中的结果之前处理无 Internet 连接错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32580412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:38:50  来源:igfitidea点击:

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

iosswiftswift2alamofire

提问by JayVDiyk

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.

Alamofire 没有网络连接时出现错误应该如何处理。我尝试检查数据是否为零,但它不起作用。

Below is how I use Alamofire

以下是我如何使用 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;

}

采纳答案by ergoon

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

我同意@Shripada。首先,您应该使用 Reachability 检查连通性。这里有一个 Swift 库:https: //github.com/ashleymills/Reachability.swift

additionally you can use one of the Alamofire validation methods:

此外,您可以使用 Alamofire 验证方法之一:

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
}

回答by AndreasLukas

Swift 3 Solution

Swift 3 解决方案

Assuming you have an Errorinstance you can do the following:

假设您有一个Error实例,您可以执行以下操作:

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

You simply cast errorinto a URLError. This works since URLErrorimplements the Errorprotocol. Here is a quote from the apple documentation for reference:

您只需将其error转换为URLError. 这是因为URLError实现了Error协议。这是苹果文档中的引用以供参考:

URLError: Describes errors in the URL error domain.

URLError:描述 URL 错误域中的错误。

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

一旦你有了一个URLError实例,你就可以简单地将它的code属性(URLError.Code枚举)与任何相关的枚举情况(在我们的示例中URLError.Code.notConnectedToInternet)进行比较。

回答by Melvin

This works for me in Swift2.x

这在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
            }
    }
}

回答by SwiftStudier

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(
<key>NSAppTransportSecurity</key>
    <dict>
    <key>NSAllowsArbitraryLoads</key><true/>
</dict>
)) }) 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()

回答by Vasily Bodnarchuk

Details

细节

  • Xcode 10.2.1 (10E1001), Swift 5
  • Xcode 10.2.1 (10E1001),Swift 5

Prepare

准备

Edit NSAppTransportSecurityin Info.plist:

在 Info.plist 中编辑NSAppTransportSecurity

Code:

代码:

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 1 (need Alamofirepod)

示例 1(需要Alamofirepod)

Use Network Reachability

使用网络可达性

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 2 (need Alamofirepod)

示例 2(需要Alamofirepod)

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 3 (without third party library)

示例 3(无第三方库)

More info: How to use SCNetworkReachability in Swift

更多信息:如何在 Swift 中使用 SCNetworkReachability

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

Sample 4 (need Reachability.swiftpod)

示例 4(需要Reachability.swiftpod)

.catchError { (error: Error) in
                    if let err = error as? URLError, err.code  == URLError.Code.notConnectedToInternet {
                        // No internet
                    } else {
                        // Other errors
                    }
                }

回答by NSnik

It works in swift 5

它适用于 swift 5

##代码##