当我试着在我的iPhone上检查网络连接时,我得到了一堆错误。有人能帮我解决这个问题吗?

代码:

import Foundation
import SystemConfiguration

public class Reachability {

class func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    }

    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
}

}

代码的错误:

如果它是不可读的,错误1说:

'Int'不能转换为'SCNetworkReachabilityFlags'

错误2和3:

找不到一个超载的'init'接受提供的参数


当前回答

There is no real way to do this, even APIs that do this will try to connect to a particular service and tell you if it succeed after previously failing, the best approach is to just try to connect to your service and handle the error appropriately, if you want some service that will notify you when you become connected, all that will happens is that it periodically calls to a fixed service until it gets a response and then let you know that it succeed, what if the problem is not the internet itself but the specific service you are trying to connect to.

最好的方法是在你的连接方法中设计处理这个问题的方法,你可以在给定的时间内触发重试,这取决于你的错误,也许是失败的数量,你可以返回一个错误,你可以用它来显示一个错误消息,给用户一个重试的可能性,也许是尝试几次,然后返回和错误的组合。

另一个类似的问题是发送你已经发送但还没有得到响应的消息,最好还是写你的应用程序来处理这个,忽略请求,直到它等待的请求返回,如果请求不同,取消等待请求,等等

这些东西可以以非常通用的方式编写,所以它们可以用于应用程序的许多不同方面,甚至不同的项目。

其他回答

这是我的版本。本质上,它没有带来任何新东西。我把它绑定到UIDevice。

import UIKit
import SystemConfiguration

extension UIDevice {

    open class var isConnectedToNetwork: Bool {
        get {
            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)

            guard
                let defaultRouteReachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
                    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                        SCNetworkReachabilityCreateWithAddress(nil, $0)
                    }
                }),
                var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags() as SCNetworkReachabilityFlags?,
                SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
                else { return false }

            return flags.contains(.reachable) && !flags.contains(.connectionRequired)
        }
    }

}

print("Network status availability: " + ( UIDevice.isConnectedToNetwork ? "true" : "false" ))

我已经检查了实现阿什利米尔的可达性类没有可可荚/依赖管理器。其思想是使项目中的可达性依赖项免费。

Xcode 7.2 - Swift 2.1

1) https://github.com/ashleymills/Reachability.swift。下载将Reachability类添加到项目中。

注:添加时,请确保勾选“如需复制项目”。

2)创建一个AppManager.swift类。这个类将迎合公共模型类,其中公共方法和数据将被添加,可以在任何VC中使用。

//  AppManager.swift

import UIKit
import Foundation

class AppManager: NSObject{
    var delegate:AppManagerDelegate? = nil
    private var _useClosures:Bool = false
    private var reachability: Reachability?
    private var _isReachability:Bool = false
    private var _reachabiltyNetworkType :String?

    var isReachability:Bool {
        get {return _isReachability}
    }  
   var reachabiltyNetworkType:String {
    get {return _reachabiltyNetworkType! }
   }   




    // Create a shared instance of AppManager
    final  class var sharedInstance : AppManager {
        struct Static {
            static var instance : AppManager?
        }
        if !(Static.instance != nil) {
            Static.instance = AppManager()

        }
        return Static.instance!
    }

    // Reachability Methods
    func initRechabilityMonitor() {
        print("initialize rechability...")
        do {
            let reachability = try Reachability.reachabilityForInternetConnection()
            self.reachability = reachability
        } catch ReachabilityError.FailedToCreateWithAddress(let address) {
            print("Unable to create\nReachability with address:\n\(address)")
            return
        } catch {}
        if (_useClosures) {
            reachability?.whenReachable = { reachability in
                self.notifyReachability(reachability)
            }
            reachability?.whenUnreachable = { reachability in
                self.notifyReachability(reachability)
            }
        } else {
            self.notifyReachability(reachability!)
        }

        do {
            try reachability?.startNotifier()
        } catch {
            print("unable to start notifier")
            return
        }


    }        
    private func notifyReachability(reachability:Reachability) {
        if reachability.isReachable() {
            self._isReachability = true

//Determine Network Type 
      if reachability.isReachableViaWiFi() {   
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WIFI_NETWORK.rawValue
      } else {
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WWAN_NETWORK.rawValue
      }

        } else {
            self._isReachability = false
self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.OTHER.rawValue

        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: ReachabilityChangedNotification, object: reachability)
    }
    func reachabilityChanged(note: NSNotification) {
        let reachability = note.object as! Reachability
        dispatch_async(dispatch_get_main_queue()) {
            if (self._useClosures) {
                self.reachability?.whenReachable = { reachability in
                    self.notifyReachability(reachability)
                }
                self.reachability?.whenUnreachable = { reachability in
                    self.notifyReachability(reachability)
                }
            } else {
                self.notifyReachability(reachability)
            }
            self.delegate?.reachabilityStatusChangeHandler(reachability)
        }
    }
    deinit {
        reachability?.stopNotifier()
        if (!_useClosures) {
            NSNotificationCenter.defaultCenter().removeObserver(self, name: ReachabilityChangedNotification, object: nil)
        }
    }
}

3)创建一个委托类。我使用委托方法来通知连接状态。

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

4)创建UIViewController的父类(继承方法)。父类具有所有子vc都可以访问的方法。

//  UIappViewController.swift

    import UIKit

    class UIappViewController: UIViewController,AppManagerDelegate {
        var manager:AppManager = AppManager.sharedInstance

        override func viewDidLoad() {
            super.viewDidLoad()
            manager.delegate = self
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        func reachabilityStatusChangeHandler(reachability: Reachability) {
            if reachability.isReachable() {
                print("isReachable")
            } else {
                print("notReachable")
            }
        }
    }

5)在AppDelegate中启动实时Internet连接监控。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    AppManager.sharedInstance.initRechabilityMonitor()
return true
}

6)我已经添加了一个Swift文件名AppReference来存储常量enum值。

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

  case WIFI_NETWORK = "Wifi"
  case WWAN_NETWORK = "Cellular"
  case OTHER = "Other"

}

7)在ViewController上(例如,你只想在网络可用的情况下调用API)

//  ViewController.swift

        import UIKit

class ViewController: UIappViewController {
  var reachability:Reachability?

  override func viewDidLoad() {
    super.viewDidLoad()
    manager.delegate = self

    if(AppManager.sharedInstance.isReachability)
    {
      print("net available")
      //call API from here.

    } else {
      dispatch_async(dispatch_get_main_queue()) {
        print("net not available")
        //Show Alert
      }
    }


    //Determine Network Type
    if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
    {
      print(".Wifi")
    }
    else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
    {
      print(".Cellular")
    }
    else {
      dispatch_async(dispatch_get_main_queue()) {
        print("Network not reachable")
      }
    }

  }
  override func viewWillAppear(animated: Bool) {
  }
  override func didReceiveMemoryWarning() {
  }
}

样本可以在https://github.com/alvinreuben/Reachability-Sample上下载

升级到Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3

这些答案中有许多已经不再适用。

原因是使用vpn(因为冠状病毒,我们现在通过vpn而不是公司的wifi进行测试)

使用苹果的网络框架,并基于这里的代码https://medium.com/@udaykiran.munaga/swift-check-for-internet-connectivity-14e355fa10c5,我能够分别检测到wifi和蜂窝网络。由于使用vpn,路径通常保持满意,因此isConnectedToNetwork()总是返回true。

下面的代码使用了apple Network框架,但重新编写,以便在现有代码中仍然使用Reachability.isConnectedToNetwork()。

    import Network

class Reachability {
    static let shared = Reachability()

    let monitorForWifi = NWPathMonitor(requiredInterfaceType: .wifi)
    let monitorForCellular = NWPathMonitor(requiredInterfaceType: .cellular)
    private var wifiStatus: NWPath.Status = .requiresConnection
    private var cellularStatus: NWPath.Status = .requiresConnection
    var isReachable: Bool { wifiStatus == .satisfied || isReachableOnCellular }
    var isReachableOnCellular: Bool { cellularStatus == .satisfied }

    func startMonitoring() {
        monitorForWifi.pathUpdateHandler = { [weak self] path in
            self?.wifiStatus = path.status

            if path.status == .satisfied {
                DLog.message("Wifi is connected!")
                // post connected notification
            } else {
                DLog.message("No wifi connection.")
                // post disconnected notification
            }
        }
        monitorForCellular.pathUpdateHandler = { [weak self] path in
            self?.cellularStatus = path.status

            if path.status == .satisfied {
                DLog.message("Cellular connection is connected!")
                // post connected notification
            } else {
                DLog.message("No cellular connection.")
                // post disconnected notification
            }
        }

        let queue = DispatchQueue(label: "NetworkMonitor")
        monitorForCellular.start(queue: queue)
        monitorForWifi.start(queue: queue)
    }

    func stopMonitoring() {
        monitorForWifi.cancel()
        monitorForCellular.cancel()
    }
    
    class func isConnectedToNetwork() -> Bool {
        return shared.isReachable
    }
}

然后在你的Appdelegate中didFinishLaunchingWithOptions: start monitoring。

Reachability.shared.startMonitoring()

如果你正在使用Alamofire,你可以这样做:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15 //Set timeouts in sec
configuration.timeoutIntervalForResource = 15

let alamoFireManager = Alamofire.Manager(configuration:configuration)
alamoFireManager?.request(.GET, "https://yourURL.com", parameters: headers, encoding: .URL)
                     .validate()
                              .responseJSON { response in

                                if let error = response.result.error {
                                   switch error.code{
                                    case -1001:
                                        print("Slow connection")
                                        return
                                    case -1009:
                                        print("No Connection!")
                                        return
                                    default: break
                                    }
                                }

虽然没有直接回答你的问题,但我想提一下苹果公司最近有这样一个谈话:

https://developer.apple.com/videos/play/wwdc2018/714/

大约在9点55分,他谈到了做你正在问的事情:

检查连接 如果连接->做点什么 如果没有连接->执行其他操作(等待?重试?)

然而,这有一些陷阱:

如果在第二步中,它说它有连接,但0.5秒后他就没有了呢? 如果用户在代理的后面呢 最后但并非最不重要的是,如果这里的一些答案不能确定连通性呢?(我敢肯定,如果你快速切换你的连接,去wi-fi,然后关掉它(只是让它变得复杂),它几乎永远不能正确地判断我是否获得了连接)。 视频中说:“没有办法保证未来的行动是否会成功。”

以下是苹果公司的一些最佳实践:

设置waitsForConnectivity为true (https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity) 响应委托方法taskIsWaitingForConnectivity (https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/2908819-urlsession)。这是苹果推荐的检查连接的方法,正如33:25的视频中提到的那样。

根据谈话,不应该有任何理由预先检查你是否有互联网连接,因为在你向服务器发送请求时,它可能并不准确。