ios 在 Swift 中使用 Reachability、NSNotification 和 Network Link Conditioner 检测网络连接变化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27310465/
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 03:54:54  来源:igfitidea点击:

Detecting Network Connectivity Changes using Reachability, NSNotification and Network Link Conditioner in Swift

iosswiftnsnotificationcenterreachability

提问by iamktothed

From iOS 12 you simply use NWPathMonitorwhich is a line of code (example).

从 iOS 12 开始,您只需使用NWPathMonitor,这是一行代码(示例)。

For historic purposes:

出于历史目的:



I'm trying to integrate network connectivitydetection into my app, however it seems that somewhere along the line I have made a mistake as my network changes are not being detected/printed out into the console.

我正在尝试将网络连接检测集成到我的应用程序中,但是似乎在此过程中的某个地方我犯了一个错误,因为我的网络更改没有被检测到/打印到控制台中。

As mentioned in the post, I'm currently using these following classes and tools for the job:

正如帖子中提到的,我目前正在使用以下这些类和工具来完成这项工作:

  1. Reachability {.h, .m}
  2. NSNotificationCenter
  3. Network Link Conditioner
  1. 可达性 {.h, .m}
  2. NSNotificationCenter
  3. 网络链路调节器

Code

代码

In the AppDelegate.Swift, I've set up the NSNotificationCenterto detect changes:

AppDelegate.Swift 中,我设置了NSNotificationCenter检测更改:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// ... 
// A: Checks if the device is connected to the internet

    var defaultCenter: Void = NSNotificationCenter().addObserver(self, selector:"checkForReachability", name: kReachabilityChangedNotification, object: nil)

}

}

In the same class AppDelegate, I've also created this function to be triggered whenever there is a change:

在同一个类中AppDelegate,我还创建了这个函数,只要有变化就会触发:

func checkForReachability () {

    var networkReachability = Reachability.reachabilityForInternetConnection()
    networkReachability.startNotifier()

    var remoteHostStatus = networkReachability.currentReachabilityStatus()
    if (remoteHostStatus.value == NotReachable.value) {
        println("Not Reachable")
    } else if (remoteHostStatus.value == ReachableViaWiFi.value) {
        println("Reachable via Wifi")
    } else {
        println("Reachable")
    }
}

However, when using the Network Link Conditioner to manipulate and simulate changes in conditions, I haven't been able to see any of those changes reflected in the console. Any help would be swell!

但是,当使用 Network Link Conditioner 来操纵和模拟条件变化时,我无法在控制台中看到任何这些变化。任何帮助都会膨胀!

回答by A. R. Younce

You must create a Reachability object beforeyou can receive notifications from it. Also, be sure to call the startNotifier()method on the Reachability object you create. This would be an example of how to do so inside of your application delegate:

您必须先创建 Reachability 对象,然后才能从它接收通知。此外,请务必startNotifier()在您创建的 Reachability 对象上调用该方法。这将是如何在您的应用程序委托中执行此操作的示例:

class AppDelegate: UIResponder, UIApplicationDelegate
{
    private var reachability:Reachability!;

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool
    {
        NSNotificationCenter.defaultCenter().addObserver(self, selector:"checkForReachability:", name: kReachabilityChangedNotification, object: nil);

        self.reachability = Reachability.reachabilityForInternetConnection();
        self.reachability.startNotifier();
    }

    @objc func checkForReachability(notification:NSNotification)
    {
        // Remove the next two lines of code. You cannot instantiate the object
        // you want to receive notifications from inside of the notification
        // handler that is meant for the notifications it emits.

        //var networkReachability = Reachability.reachabilityForInternetConnection()
        //networkReachability.startNotifier()

        let networkReachability = notification.object as Reachability;
        var remoteHostStatus = networkReachability.currentReachabilityStatus()

        if (remoteHostStatus.value == NotReachable.value)
        {
            println("Not Reachable")
        }
        else if (remoteHostStatus.value == ReachableViaWiFi.value)
        {
            println("Reachable via Wifi")
        }
        else
        {
            println("Reachable")
        }
    }
}

I recommend you take a look at the documentation for NSNotificationCenterand NSNotification. That way you'll be more familiar with how to work with notifications next time something like this comes up.

我建议您查看NSNotificationCenterNSNotification的文档。这样,您将更熟悉如何在下次出现此类通知时使用通知。

Swift 3

斯威夫特 3

NotificationCenter.default.addObserver(self, selector:Selector(("checkForReachability:")), name: NSNotification.Name.reachabilityChanged, object: nil)
let reachability: Reachability = Reachability.forInternetConnection()
reachability.startNotifier()

回答by AnthonyR

Updated for Swift 4 / Swift 5 according @Hardik.T

根据@Hardik.T 为 Swift 4 / Swift 5 更新

1.Import Reachability.swiftfile from https://github.com/ashleymills/Reachability.swift/archive/master.zipin your XCode project

1.Reachability.swifthttps://github.com/ashleymills/Reachability.swift/archive/master.zip在您的 XCode 项目中导入文件

2.Create a new Swift class : ConnectionManager.swift

2.创建一个新的 Swift 类:ConnectionManager.swift

class ConnectionManager {

static let sharedInstance = ConnectionManager()
private var reachability : Reachability!

func observeReachability(){
    self.reachability = Reachability()
    NotificationCenter.default.addObserver(self, selector:#selector(self.reachabilityChanged), name: NSNotification.Name.reachabilityChanged, object: nil)
    do {
        try self.reachability.startNotifier()
    }
    catch(let error) {
        print("Error occured while starting reachability notifications : \(error.localizedDescription)")
    }
}

@objc func reachabilityChanged(note: Notification) {
    let reachability = note.object as! Reachability
    switch reachability.connection {
    case .cellular:
        print("Network available via Cellular Data.")
        break
    case .wifi:
        print("Network available via WiFi.")
        break
    case .none:
        print("Network is not available.")
        break
    case .unavailable:
        print("Network is  unavailable.")
        break
    }
  }
}

3.Use it in your AppDelegatefile :

3.在您的AppDelegate文件中使用它:

func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    ConnectionManager.sharedInstance.observeReachability()
    return true
}

回答by AndreasLukas

Instead of polluting the AppDelegate.swiftwith observer callbacks I would recommend adding observers only into the relevant view controllers.

AppDelegate.swift我建议只将观察者添加到相关的视图控制器中,而不是使用观察者回调污染。

AppDelegate.swift

AppDelegate.swift

import ReachabilitySwift


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
    var reachability: Reachability?


    func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? ) -> Bool
    {
       self.reachability = Reachability()

       do
       {
          try reachability?.startNotifier()
       }
       catch
       {
          print( "ERROR: Could not start reachability notifier." )
       }

       return true
    }


    class func sharedAppDelegate() -> AppDelegate?
    {
        return UIApplication.shared.delegate as? AppDelegate
    }


    // Remaining functions
}

Example of a ViewController:

视图控制器示例:

class ExampleVC: UIViewController
{
    override func viewDidLoad()
    {
        // Add reachability observer
        if let reachability = AppDelegate.sharedAppDelegate()?.reachability
        {
            NotificationCenter.default.addObserver( self, selector: #selector( self.reachabilityChanged ),name: ReachabilityChangedNotification, object: reachability )
        }
    }


    @objc private func reachabilityChanged( notification: NSNotification )
    {
        guard let reachability = notification.object as? Reachability else
        {
            return
        }

        if reachability.isReachable
        {
            if reachability.isReachableViaWiFi
            {
                print("Reachable via WiFi")
            }
            else
            {
                print("Reachable via Cellular")
            }
        }
        else
        {
            print("Network not reachable")
        }
    }
}

回答by gbk

Based on this open source solutionWrapped to class

基于这个开源解决方案Wrapped to class

Swift 5

斯威夫特 5

import Foundation

final class ReachabilityHandler {

  private var reachability: Reachability? = Reachability()

  // MARK: - LifeCycle

  init() {
    configure()
  }

  deinit {
    NotificationCenter.default.removeObserver(self)
    reachability?.stopNotifier()
  }

  // MARK: - Private

  private func configure() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(ReachabilityHandler.checkForReachability(notification:)),
                                           name: Notification.Name.reachabilityChanged,
                                           object: nil)
    try? reachability?.startNotifier()

  }

  @objc private func checkForReachability(notification: NSNotification) {
    let networkReachability = notification.object as? Reachability
    if let remoteHostStatus = networkReachability?.connection {
      switch remoteHostStatus {
        case .none:

        case .wifi,
             .cellular:

      }
    }
  }
}

In AppDelegate

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {

  private var rechabilityObserver: ReachabilityHandler?

  var window: UIWindow?

  // MARK: - LifeCycle

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    rechabilityObserver = ReachabilityHandler()

    return true
  }
}

回答by Sourabh Sharma

Upadated for swift 2.1 & XCode 7:

为 swift 2.1 和 XCode 7 更新:

try this third party Highly Rated Reachablity Class

试试这个第三方高评级可达性等级

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool
    {
 // Allocate a reachability object
        self.reach = Reachability.reachabilityForInternetConnection()

        // Tell the reachability that we DON'T want to be reachable on 3G/EDGE/CDMA
        self.reach!.reachableOnWWAN = false

        // Here we set up a NSNotification observer. The Reachability that caused the notification
        // is passed in the object parameter
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: "reachabilityChanged:",
            name: kReachabilityChangedNotification,
            object: nil)

        self.reach!.startNotifier()

return true
}

//Reachbality Notification Response

    func reachabilityChanged(notification: NSNotification) {
        if self.reach!.isReachableViaWiFi() || self.reach!.isReachableViaWWAN() {
            print("Service avalaible!!!")
        } else {
            print("No service avalaible!!!")

            AppHelper.showALertWithTag(0, title: constants.AppName.rawValue, message: "Please Check Your Internet Connection!", delegate: self, cancelButtonTitle: "OK", otherButtonTitle: nil)
        }
    }

回答by EPage_Ed

Updated A. R. Younce answer for Swift 2:

更新了 Swift 2 的 AR Younce 答案:

func checkForReachability(notification:NSNotification) {
    if let networkReachability = notification.object as? Reachability {
        let remoteHostStatus = networkReachability.currentReachabilityStatus()

        if (remoteHostStatus == NotReachable) {
            print("Not Reachable")
        }
        else if (remoteHostStatus == ReachableViaWiFi) {
            print("Reachable via Wifi")
        }
        else {
            print("Reachable")
        }
    } else {
        print("Unknown")
    }
}

回答by Shrikant Tanwade

Swift 2.0 - Check Network Using Reachability, NSNotification

Swift 2.0 - 使用可达性、NSNotification 检查网络

AppDelegate.swift

AppDelegate.swift

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
{
    NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(self.checkNetworkStatus(_:)), name: "ReachabilityChangedNotification", object: nil);

    do{self.reachability = try Reachability.reachabilityForInternetConnection()}catch{}
    do{try self.reachability.startNotifier()}catch{}
    self.checkNetworkStatus()

    return true
}

Declare networkStatus variable

声明 networkStatus 变量

var networkStatus : Reachability.NetworkStatus!

checkNetworkStatus() Function

checkNetworkStatus() 函数

func checkNetworkStatus()
{
    networkStatus = reachability.currentReachabilityStatus

    if (networkStatus == Reachability.NetworkStatus.NotReachable)
    {
        print("Not Reachable")
    }
    else
    {
        print("Reachable")
    }
}

OtherClass.Swift

其他类.Swift

let delegate = UIApplication.sharedApplication().delegate as! AppDelegate

if (delegate.networkStatus!=Reachability.NetworkStatus.NotReachable)
{
   // Call Webservice     
}
else
{
   delegate.checkNetworkStatus()  //Not Reachable print  
}

回答by Hardik Thakkar

1) Install pod or add ReachabilitySwiftin your project

1)在你的项目中安装 pod 或添加ReachabilitySwift

2) in AppDelegate.swift

2) 在AppDelegate.swift 中

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(self.checkForReachability(_:)), name: "ReachabilityChangedNotification", object: nil);

        do {
            try self.reachability = Reachability.reachabilityForInternetConnection()
        }
        catch {
            print(error)
        }

        do {
            try self.reachability.startNotifier()
        }
        catch {
            print(error)
        }

        return true
    }

3)

3)

func checkForReachability(notification:NSNotification) {
        let networkReachability = notification.object as! Reachability;
        let remoteHostStatus = networkReachability.currentReachabilityStatus

        if (remoteHostStatus == .NotReachable) {
            print("Not Reachable")
        }
        else if (remoteHostStatus == .ReachableViaWiFi || remoteHostStatus == .ReachableViaWWAN) {
            print("Reachable via Wifi or via WWAN")
        }
    }

回答by Suhit Patil

Using ReachabilitySwiftframework which is a replacement for Apple's Reachability re-written in Swift with closures

使用ReachabilitySwift框架替代 Apple 的 Reachability 用 Swift 重新编写的闭包

  1. Install ReachabilitySwiftCocoapod

  2. Create NetworkReachabilitywrapper class for observing the reachability changes

    import ReachabilitySwift

    extension Notification.Name {
        static let ReachabilityStatusChanged = Notification.Name("ReachabilityStatusChangedNotification")
    }
    
    //MARK: NetworkReachability
    
    final class NetworkReachability {
    
    enum ReachabilityStatus: Equatable {
        case connected
        case disconnected
    }
    
    static let shared = NetworkReachability()
    
    private let reachability = try! Reachability()
    
    var reachabilityObserver: ((ReachabilityStatus) -> Void)?
    
    private(set) var reachabilityStatus: ReachabilityStatus = .connected
    
    private init() {
        setupReachability()
    }
    
    /// setup observer to detect reachability changes
    private func setupReachability() {
        let reachabilityStatusObserver: ((Reachability) -> ()) = { [unowned self] (reachability: Reachability) in
            self?.updateReachabilityStatus(reachability.connection)
        }
        reachability.whenReachable = reachabilityStatusObserver
        reachability.whenUnreachable = reachabilityStatusObserver
    }
    
    /// Start observing reachability changes
    func startNotifier() {
        do {
            try reachability.startNotifier()
        } catch {
            print(error.localizedDescription)
        }
    }
    
    
    /// Stop observing reachability changes
    func stopNotifier() {
        reachability.stopNotifier()
    }
    
    
    /// Updated ReachabilityStatus status based on connectivity status
    ///
    /// - Parameter status: Reachability.Connection enum containing reachability status
    private func updateReachabilityStatus(_ status: Reachability.Connection) {
        switch status {
            case .unavailable, .none:
                notifyReachabilityStatus(.disconnected)
            case .cellular, .wifi:
                notifyReachabilityStatus(.connected)
        }
    }
    
    
    /// Notifies observers about reachability status change
    ///
    /// - Parameter status: ReachabilityStatus enum indicating status eg. .connected/.disconnected
    private func notifyReachabilityStatus(_ status: ReachabilityStatus) {
        reachabilityStatus = status
        reachabilityObserver?(status)
        NotificationCenter.default.post(
            name: Notification.Name.ReachabilityStatusChanged,
            object: nil,
            userInfo: ["ReachabilityStatus": status]
        )
    }
    
    /// returns current reachability status
    var isReachable: Bool {
        return reachability.connection != .unavailable
    }
    
    
    /// returns if connected via cellular or wifi
    var isConnectedViaCellularOrWifi: Bool {
        return isConnectedViaCellular || isConnectedViaWiFi
    }
    
    /// returns if connected via cellular
    var isConnectedViaCellular: Bool {
        return reachability.connection == .cellular
    }
    
    /// returns if connected via cellular
    var isConnectedViaWiFi: Bool {
        return reachability.connection == .wifi
    }
    
    deinit {
        stopNotifier()
    } 
    

    }

    in AppDelagete.Swift

    func application(_ application: UIApplication,
                         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     NetworkReachability.shared.startNotifier()
     reahabilityObserver()
    }
    
    func reachabilityObserver() {
    
      NetworkReachability.shared.reachabilityObserver = { [weak self] status in
            switch status {
                case .connected:
                    print("Reachability: Network available ")
                case .disconnected:
                    print("Reachability: Network unavailable ")
            }
        }
    }
    
  1. 安装ReachabilitySwiftCocoapod

  2. 创建NetworkReachability包装类以观察可达性变化

    导入 ReachabilitySwift

    extension Notification.Name {
        static let ReachabilityStatusChanged = Notification.Name("ReachabilityStatusChangedNotification")
    }
    
    //MARK: NetworkReachability
    
    final class NetworkReachability {
    
    enum ReachabilityStatus: Equatable {
        case connected
        case disconnected
    }
    
    static let shared = NetworkReachability()
    
    private let reachability = try! Reachability()
    
    var reachabilityObserver: ((ReachabilityStatus) -> Void)?
    
    private(set) var reachabilityStatus: ReachabilityStatus = .connected
    
    private init() {
        setupReachability()
    }
    
    /// setup observer to detect reachability changes
    private func setupReachability() {
        let reachabilityStatusObserver: ((Reachability) -> ()) = { [unowned self] (reachability: Reachability) in
            self?.updateReachabilityStatus(reachability.connection)
        }
        reachability.whenReachable = reachabilityStatusObserver
        reachability.whenUnreachable = reachabilityStatusObserver
    }
    
    /// Start observing reachability changes
    func startNotifier() {
        do {
            try reachability.startNotifier()
        } catch {
            print(error.localizedDescription)
        }
    }
    
    
    /// Stop observing reachability changes
    func stopNotifier() {
        reachability.stopNotifier()
    }
    
    
    /// Updated ReachabilityStatus status based on connectivity status
    ///
    /// - Parameter status: Reachability.Connection enum containing reachability status
    private func updateReachabilityStatus(_ status: Reachability.Connection) {
        switch status {
            case .unavailable, .none:
                notifyReachabilityStatus(.disconnected)
            case .cellular, .wifi:
                notifyReachabilityStatus(.connected)
        }
    }
    
    
    /// Notifies observers about reachability status change
    ///
    /// - Parameter status: ReachabilityStatus enum indicating status eg. .connected/.disconnected
    private func notifyReachabilityStatus(_ status: ReachabilityStatus) {
        reachabilityStatus = status
        reachabilityObserver?(status)
        NotificationCenter.default.post(
            name: Notification.Name.ReachabilityStatusChanged,
            object: nil,
            userInfo: ["ReachabilityStatus": status]
        )
    }
    
    /// returns current reachability status
    var isReachable: Bool {
        return reachability.connection != .unavailable
    }
    
    
    /// returns if connected via cellular or wifi
    var isConnectedViaCellularOrWifi: Bool {
        return isConnectedViaCellular || isConnectedViaWiFi
    }
    
    /// returns if connected via cellular
    var isConnectedViaCellular: Bool {
        return reachability.connection == .cellular
    }
    
    /// returns if connected via cellular
    var isConnectedViaWiFi: Bool {
        return reachability.connection == .wifi
    }
    
    deinit {
        stopNotifier()
    } 
    

    }

    AppDelagete.Swift 中

    func application(_ application: UIApplication,
                         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     NetworkReachability.shared.startNotifier()
     reahabilityObserver()
    }
    
    func reachabilityObserver() {
    
      NetworkReachability.shared.reachabilityObserver = { [weak self] status in
            switch status {
                case .connected:
                    print("Reachability: Network available ")
                case .disconnected:
                    print("Reachability: Network unavailable ")
            }
        }
    }