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
Detecting Network Connectivity Changes using Reachability, NSNotification and Network Link Conditioner in Swift
提问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:
正如帖子中提到的,我目前正在使用以下这些类和工具来完成这项工作:
- Reachability
{.h, .m}
NSNotificationCenter
- Network Link Conditioner
- 可达性
{.h, .m}
NSNotificationCenter
- 网络链路调节器
Code
代码
In the AppDelegate.Swift, I've set up the NSNotificationCenter
to 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.
我建议您查看NSNotificationCenter和NSNotification的文档。这样,您将更熟悉如何在下次出现此类通知时使用通知。
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.swift
file from https://github.com/ashleymills/Reachability.swift/archive/master.zipin your XCode project
1.Reachability.swift
从https://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 AppDelegate
file :
3.在您的AppDelegate
文件中使用它:
func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
ConnectionManager.sharedInstance.observeReachability()
return true
}
回答by AndreasLukas
Instead of polluting the AppDelegate.swift
with 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 重新编写的闭包
Install ReachabilitySwiftCocoapod
Create
NetworkReachability
wrapper class for observing the reachability changesimport 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 ") } } }
安装ReachabilitySwiftCocoapod
创建
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 ") } } }