Detecting Network Connectivity Changes using Reachability, NSNotification and Network Link Conditioner in Swift
Solution 1
You must create a Reachability object before you 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:
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 NSNotificationCenter and NSNotification. That way you'll be more familiar with how to work with notifications next time something like this comes up.
Swift 3
NotificationCenter.default.addObserver(self, selector:Selector(("checkForReachability:")), name: NSNotification.Name.reachabilityChanged, object: nil)
let reachability: Reachability = Reachability.forInternetConnection()
reachability.startNotifier()
Solution 2
Updated for Swift 4 / Swift 5 according @Hardik.T
1. Import Reachability.swift
file from https://github.com/ashleymills/Reachability.swift/archive/master.zip in your XCode project
2. Create a new Swift class : 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 :
func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
ConnectionManager.sharedInstance.observeReachability()
return true
}
Solution 3
Instead of polluting the AppDelegate.swift
with observer callbacks I would recommend adding observers only into the relevant view controllers.
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")
}
}
}
Solution 4
Based on this open source solution Wrapped to class
Swift 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
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
}
}
Solution 5
Upadated for 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)
}
}
![iamktothed](https://i.stack.imgur.com/py8Fr.png?s=256&g=1)
iamktothed
Updated on July 09, 2022Comments
-
iamktothed almost 2 years
From iOS 12 you simply use NWPathMonitor which is a line of code (example).
For historic purposes:
I'm trying to integrate network connectivity detection 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
Code
In the AppDelegate.Swift, I've set up the
NSNotificationCenter
to detect changes: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: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!
- Reachability
-
iamktothed over 9 yearsThanks, I've changed it. However, I'm still unable to detect network changes via printing to the console.
-
A. R. Younce over 9 yearsTry setting a breakpoint in checkForReachability() to see if it is getting called at all. If so then you'll know your problem has to do with the either that method or the data it receives.
-
iamktothed over 9 yearsI've set the breakpoint and it seems that it's not being called at all.
-
iamktothed over 9 yearsI've implemented the changes and it worked. I had to resort to deploying the iPhone as my Network Link Conditioner wasn't simulating the necessary changes. I'll be sure to dive into the documentation. Thanks!
-
iamktothed over 8 yearsYou should consider using a swift statement as it ensures that the exhaustive list of values are being considered. Other than that some, subjectively consider it easier to read, understand and maintain.
-
EPage_Ed over 8 yearsVery true about using Swift switch statement. In my case I just cared if it was reachable or not. However I replicated Younce's code with the fixes for the purposes of the post.
-
user2695433 over 7 yearsHi can you please show example how to pass a NSNotification to checkForReachability method to show a notification to UILabel in a ViewController
-
DàChún over 7 yearsdo we need call stopNotifier in AppDelegate?
-
A. R. Younce over 7 years@User9527 Probably, but the exact delegate method will depend on how you're using it.
-
IgniteCoders over 7 years-1! When you want to check for internet connection changed. You don't know in which view the user is. so you need to check in whole app.
-
arauter over 7 yearsI am checking the whole app. However, only the view controllers interested in an internet connection change, listen to the internet notification.
-
Khushboo Dhote about 6 yearsI am using this method. first time when I a going offline reachabilityChanged() getting called. But again if I am getting connected it is not getting called for any event. Please Help
-
Dima G over 5 yearsShouldn't we also call "NotificationCenter.default.removeObserver" when the view is not in use any more?
-
jayant rawat over 4 yearsJust a question...how to notify a view controller about network changes ?
-
Apple_Magic about 4 years@KhushbooDhote U don't need it now but still posting answer to help any needy...Simulator works in weird way and calling notifier only once...to get notify for each internet connection change debug on real device