如何在alamofire中检查网络连接?

41

我正在使用以下代码在服务器上发起HTTP请求。现在我想知道它是否已连接到互联网。以下是我的代码:

  let request = Alamofire.request(completeURL(domainName: path), method: method, parameters: parameters, encoding: encoding.value, headers: headers)
      .responseJSON {


        let resstr = NSString(data: $0.data!, encoding: String.Encoding.utf8.rawValue)
        print("error is \(resstr)")


        if $0.result.isFailure {
          self.failure("Network")
          print("API FAILED 4")
          return
        }
        guard let result = $0.result.value else {
          self.unKnownError()
          self.failure("")
          print("API FAILED 3")

          return
        }
        self.handleSuccess(JSON(result))
    }

你可以使用网络可达性 - Hamza Ansari
你可能想查看这个答案 - Ahmad F
可能是 检查互联网连接的可用性? 的重复。 - TajyMany
9个回答

105

适用于Swift 5和Alamofire 5.4.4,我创建了一个名为Connectivity的Swift类。使用Alamofire中的NetworkReachabilityManager类,并根据需要configure isConnectedToInternet()方法。

import Foundation
import Alamofire

class Connectivity {
    class func isConnectedToInternet() -> Bool {
        return NetworkReachabilityManager()?.isReachable ?? false
    }
}

使用方法:

if Connectivity.isConnectedToInternet() {
        print("Yes! internet is available.")
        // do some tasks..
 }

编辑: 由于Swift鼓励使用计算属性,因此您可以将上述函数更改为:

import Foundation
import Alamofire
class Connectivity {
    class var isConnectedToInternet:Bool {
        return NetworkReachabilityManager()?.isReachable ?? false
    }
}

并像这样使用:

if Connectivity.isConnectedToInternet {
        print("Yes! internet is available.")
        // do some tasks..
 }

简单、可工作和可重用。不过,我不确定是否最好将其制作为协议,并在需要的地方进行扩展和覆盖。 - Andreas777
我从未使用过 class var。这样做和 shared let 有什么区别?我知道它们不同,只是不确定具体差别! - mfaani
1
我刚刚创建了一个计算变量,可以直接在类类型上调用。你也可以使用静态变量,在这种情况下更好。你说的 shared let 是什么意思? - abhimuralidharan
3
这实际上是行不通的。它只是检查移动数据或WiFi是否连接,但未检查“真正的互联网”是否可用。创建一个没有互联网的热点,它会显示已连接。 - Anuran Barman

25

Swift 2.3

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

Swift 3.0

  Alamofire.upload(multipartFormData: { multipartFormData in
    }, to: URL, method: .post,headers: nil,
       encodingCompletion:  { (result) in
        switch result {

        case .success( _, _, _): break

        case .failure(let encodingError ):
            print(encodingError)

            if let err = encodingError as? URLError, err.code == .notConnectedToInternet {
                // no internet connection
                print(err)
            } else {
                // other failures
            }

        }
    })

使用 NetworkReachabilityManager

let networkReachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.apple.com")

func checkForReachability() {
    self.networkReachabilityManager?.listener = { status in
        print("Network Status: \(status)")
        switch status {
        case .notReachable:
            //Show error here (no internet connection)
        case .reachable(_), .unknown:
            //Hide error here
        }
    }

    self.networkReachabilityManager?.startListening()
}

//How to Use : Just call below function in required class
if checkForReachability() {
   print("connected with network")
}

每次我第一次调用这个函数时,无论互联网连接的状态如何,它都会返回.reachable true。 - Khadija Daruwala

21

对于Swift 3/4版本,

在Alamofire中,有一个名为NetworkReachabilityManager的类,可以用于观察或检查互联网是否可用。

let reachabilityManager = NetworkReachabilityManager()

reachabilityManager?.startListening()
reachabilityManager?.listener = { _ in
        if let isNetworkReachable = self.reachabilityManager?.isReachable,
            isNetworkReachable == true {
            //Internet Available
        } else {
            //Internet Not Available"
        }
    }

在这里,每当互联网的状态发生变化时,侦听器将被调用。您可以根据自己的需求进行处理。


1
可达性管理器(reachabilityManager)需要在deint()中被解除初始化吗? - Sujal
1
@Sujal 这取决于您的用例,如果您想将其整合到整个应用程序中,则不需要,因为您将在AppDelegate中声明。如果您的用例是单次使用,则可以使用deinit NetworkReachabilityManager。 - Parth Adroja
2
在互联网上有很多答案,但是这个对我起作用。(请注意,在模拟器中它不完美,但在实际手机上它运行得非常好。) - Derence

3
一般来说,如果您可以从实际调用中获取互联网离线信息,则比可达性更好。您可以确定实际的API调用失败是因为互联网断开了连接。如果在调用API之前测试可达性并失败,则您只知道在进行测试时互联网处于离线状态(或者Apple宕机),而不知道在进行调用时互联网是否将处于离线状态。您可能认为在可达性调用返回后几毫秒内,或者在检索存储的值后,但事实上这是不确定的。操作系统可能已安排一些任意数量的线程,在可达性在其闭包中返回其值之前更新任何全局变量。
而且,可达性在其自身代码中历史上存在错误。
这并不是说您不应该使用alamofire的NetworkReachabilityManager来更改UI、监听它并更新所有UI组件。
但是,如果您有理由调用API,则在API层中测试可达性是多余的,或者可能会导致一些微妙的错误。

展示如何切换AFError以仅获取无网络错误。 - Lukasz D

3
如果Alamofire.upload的结果返回成功,那么在上传图像时检查互联网可用性的方法如下:
Alamofire.upload(multipartFormData: { multipartFormData in

                for (key,value) in parameters {
                 multipartFormData.append((value).data(using: .utf8)!, withName: key)
                }
                  multipartFormData.append(self.imageData!, withName: "image" ,fileName: "image.jpg" , mimeType: "image/jpeg")
            }, to:url)
            { (result) in

                switch result{

                case .success(let upload, _, _):

                    upload.uploadProgress(closure: { (progress) in
                     print("Upload Progress: \(progress.fractionCompleted)")

                    })

                    upload.responseJSON { response in
                        if  let statusCode = response.response?.statusCode{

                        if(statusCode == 201){
                         //internet available
                          }
                        }else{
                        //internet not available

                        }
                    }

                case .failure(let encodingError):
                    print(encodingError)

                }

            }

3
如果你前往NetworkReachabilityManager.swift文件,你会看到以下内容:

/// 当前网络是否可达。 public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi }

因此,我在我的APIhandlerClass中编写了以下内容:
import AlamofireNetworkActivityIndicator

private let manager = NetworkReachabilityManager(host: "www.apple.com")

func isNetworkReachable() -> Bool {
    return manager?.isReachable ?? false
}

这告诉我网络的状态。


请仅使用Alamofire提供解决方案。 - TechChain
它是Alamofire的一部分。 - Umair Afzal

1

使用Alamofire的RequestAdapter类,在没有网络连接时抛出错误

class RequestInterceptor : RequestAdapter{
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {

    let reachable = NetworkReachabilityManager()?.isReachable ?? false
    if !reachable{
        throw NSError.NoInternet
    }
    var nUrlRequest = urlRequest
    // modify request if needed 
    return nUrlRequest
   }
}

extension NSError  {

static func createWithLocalizedDesription(withCode code:Int = 204,localizedDescription:String) -> NSError{
    return  NSError(domain: "<your bundle id>", code:code, userInfo: [NSLocalizedDescriptionKey : localizedDescription])
}
static var NoInternet : NSError {
    return createWithLocalizedDesription(withCode: -1009,localizedDescription:"Please check your internet connection")
}

}

现在将适配器设置为 Alamofire Session Manager
let sessionManager = Alamofire.SessionManager(configuration: configuration)

sessionManager.adapter = RequestInterceptor()

现在每次创建 Alamofire 请求 时,在 DataResponse 中捕获错误。这个机制将适用于所有请求。

2
不要使用Reachability来确定是否应该发送网络请求。您应该始终发送它。参考:https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#network-reachability - Ted

1
  func isConnectedToNetwork()-> Bool {

    var zeroAddress = sockaddr_in()
    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)
        }
    }
    //Commented code only work upto iOS Swift 2.3
    //    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
    //
    //        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    //    }

    var flags = SCNetworkReachabilityFlags()
    if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
        return false
    }
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
}
    // Call api method
    func callApi(){
        if isConnectedToNetwork() {  // Network Connection status
            // Call your request here
        }else{
            //"Your Internet connection is not active at this time."
        }
    }

我想要使用Alamofire来完成,而不是使用Reachability。 - TechChain
让reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.apple.com")函数listenForReachability() { reachabilityManager?.listener = { status in print("网络状态已更改:(status)") switch status { case .NotReachable: break //显示错误状态 case .Reachable(_), .Unknown: break //隐藏错误状态 } }reachabilityManager?.startListening()} - MAhipal Singh
我无法遵循这种方法,请审核我的代码并提供解决方案。 - TechChain

0
在Alamofire 5中,当错误类型为AFError时,您可以像这样进行切换:
 case .failure(let error):  // error is type of AFError
                    if error.isSessionTaskError {
                      // seems that one only get triggered when no internet 
                        print("Session task error")
                        print(error.localizedDescription)
                        }
                    switch error.responseCode {
                    case 401:
                        print("401 token invalid or expired")
                    default:
                        print("Error : \(error.responseCode ?? 0)")
                        print(error.localizedDescription)
                    }
                    print("All other errors:\(error)")
                case .finished:
                    break
                }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接