Swift iOS- What to do when there is a wifi connection but no internet connection?
I'm using Alamofire in my iOS app. I use bool values in viewWillAppear and in AppDelegate with NSNotifications to check if there is an internet connection. If there is no wifi connection a pop up appears to inform the user. If there is a wifi connection the pop up disappears and everything works fine again. I've had no problems as long as wifi is clearly not working.
I was at a meetup and someone explained to me that the way it works is it it looks for a wifi connection and not an internet connection. For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet.
I was just in a situation where I connected to an open network, my app initially responded as if I were actually connected to the internet (no pop up) but I couldn't get connect to anything. The wifi signal was on full. In terminal I ran a ping and it turns out the connection was dead. My app couldn't tell the difference.


How do I make a pop up appear in a sitaution like this?
Also what is .case unknown for?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
SomeVC:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
ios networking alamofire reachability nsnotifications
add a comment |
I'm using Alamofire in my iOS app. I use bool values in viewWillAppear and in AppDelegate with NSNotifications to check if there is an internet connection. If there is no wifi connection a pop up appears to inform the user. If there is a wifi connection the pop up disappears and everything works fine again. I've had no problems as long as wifi is clearly not working.
I was at a meetup and someone explained to me that the way it works is it it looks for a wifi connection and not an internet connection. For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet.
I was just in a situation where I connected to an open network, my app initially responded as if I were actually connected to the internet (no pop up) but I couldn't get connect to anything. The wifi signal was on full. In terminal I ran a ping and it turns out the connection was dead. My app couldn't tell the difference.


How do I make a pop up appear in a sitaution like this?
Also what is .case unknown for?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
SomeVC:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
ios networking alamofire reachability nsnotifications
add a comment |
I'm using Alamofire in my iOS app. I use bool values in viewWillAppear and in AppDelegate with NSNotifications to check if there is an internet connection. If there is no wifi connection a pop up appears to inform the user. If there is a wifi connection the pop up disappears and everything works fine again. I've had no problems as long as wifi is clearly not working.
I was at a meetup and someone explained to me that the way it works is it it looks for a wifi connection and not an internet connection. For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet.
I was just in a situation where I connected to an open network, my app initially responded as if I were actually connected to the internet (no pop up) but I couldn't get connect to anything. The wifi signal was on full. In terminal I ran a ping and it turns out the connection was dead. My app couldn't tell the difference.


How do I make a pop up appear in a sitaution like this?
Also what is .case unknown for?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
SomeVC:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
ios networking alamofire reachability nsnotifications
I'm using Alamofire in my iOS app. I use bool values in viewWillAppear and in AppDelegate with NSNotifications to check if there is an internet connection. If there is no wifi connection a pop up appears to inform the user. If there is a wifi connection the pop up disappears and everything works fine again. I've had no problems as long as wifi is clearly not working.
I was at a meetup and someone explained to me that the way it works is it it looks for a wifi connection and not an internet connection. For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet.
I was just in a situation where I connected to an open network, my app initially responded as if I were actually connected to the internet (no pop up) but I couldn't get connect to anything. The wifi signal was on full. In terminal I ran a ping and it turns out the connection was dead. My app couldn't tell the difference.


How do I make a pop up appear in a sitaution like this?
Also what is .case unknown for?
Alamofire.Swift:
import Foundation
import Alamofire
open class NetworkManager {
open static var sharedManager: NetworkReachabilityManager = {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.listener = { (status) in
switch status {
case .notReachable:
print("The network is not reachable")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "unsuccessful"), object: nil)
case .unknown : //???????
print("It is unknown wether the network is reachable")
//I'm not sure whether to put a Notification for successful or unsuccessful???
case .reachable(.ethernetOrWiFi):
print("The network is reachable over the WiFi connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
case .reachable(.wwan):
print("The network is reachable over the WWAN connection")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "successful"), object: nil)
}
}
reachabilityManager?.startListening()
return reachabilityManager!
}()
}
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NetworkManager.sharedManager.startListening()
SomeVC:
override func viewWillAppear() {
super.viewWillAppear()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(successful), name: "successful", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(unsuccessful), name: "unsuccessful", object: nil)
if NetworkManager.sharedManager.isReachable == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnWWAN == true{
self.successful()
}else{
self.unsuccessful()
}
if NetworkManager.sharedManager.isReachableOnEthernetOrWiFi == true{
self.successful()
}else{
self.unsuccessful()
}
}
func successful(){
//dismiss pop up
}
func unsuccessful(){
//show pop up
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "successful", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "unsuccessful", object: nil)
}
}
ios networking alamofire reachability nsnotifications
ios networking alamofire reachability nsnotifications
edited May 9 '18 at 12:08
Lance Samaria
asked Mar 28 '17 at 10:58
Lance SamariaLance Samaria
2,52921451
2,52921451
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
You can init NetworkReachabilityManagerwith host, for example, google host, because default is 0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
When you start listening reachability manager doing ping to host. If network is available you can cache SSID and ping again when SSID changed.
For case .unknown better put a Notification for unsuccessful.
Example get SSID (it doesn't work in Simulator):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManagerguard let ssid = fetchSSIDInfo() else {return} //save ssid
– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
|
show 9 more comments
Here's an answer composed of these 2 solutions:Pavle Mijatovic and Yasin Ugurlu
Make a new class and name it Connection and copy and paste the code below inside of it:
import Foundation
import SystemConfiguration
class Connection {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return isReachable && !needsConnection
}
class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {
// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
completionHandler(false)
return
}
// 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
webAddress = webSiteToPing!
}
guard let url = URL(string: webAddress) else {
completionHandler(false)
print("could not create url from: (webAddress)")
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
if error != nil || response == nil {
completionHandler(false)
} else {
completionHandler(true)
}
})
task.resume()
}
}
In whatever view controller your using it in inside viewDidLoad call it like this:
override func viewDidLoad() {
super.viewDidLoad()
// if in china usewww.apple.com or www.alibaba.com instead
Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: {
(bool) in
if bool{
print("Internet connection is good")
}else{
print("No internet connection can be found")
}
})
}
A couple of things I've found out is this only seems to work once because if a connection is available "Internet connection is good" prints but if I go to airplane mode "No internet connection can be found" doesn't print. It's not actively listening which makes me think I have to hook up to a Notification? The other thing is if your in China then this will not work because google isn't available in China. Maybe a better website to check would be www.apple.com or www.alibaba.com as it seems they're available everywhere.
Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"...
or
Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"...
add a comment |
I followed this AshleyMills Reachability file and it uses google.com to test for a connection. You can just copy and paste the below inside a new file to test to see how it works. If your using this in China then use alibaba.com because google isn't available in China.
// everywhere outside China
let hostNames = [nil, "google.com", "invalidhost"]
// everywhere including China
let hostNames = [nil, "alibaba.com", "invalidhost"]
When you first launch the app you will see the labels change every 5 seconds because there is an async timer inside: func startHost(at index: Int)
If you want to stop it and take control of everything yourself then comment out this code:
// comment this out to stop the connection from changing
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
//self.startHost(at: (index + 1) % 3)
}
Once you comment that out then you should toggle your phones connection between Wifi, Cellular Connection, and Airplane Mode. The label colors will change from green to blue to red depending on the connection.
Create a new project and add this to the ViewController file:
import UIKit
class ViewController: UIViewController {
let networkStatus: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Status"
label.textAlignment = .center
return label
}()
let hostNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Host"
label.textAlignment = .center
return label
}()
var reachability: Reachability?
let hostNames = [nil, "google.com", "invalidhost"]
var hostIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
startHost(at: 1)
}
func startHost(at index: Int) {
stopNotifier()
setupReachability(hostNames[index], useClosures: true)
startNotifier()
// this loops the connection every 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.startHost(at: (index + 1) % 3)
}
}
func setupReachability(_ hostName: String?, useClosures: Bool) {
let reachability: Reachability?
if let hostName = hostName {
reachability = Reachability(hostname: hostName)
hostNameLabel.text = hostName
} else {
reachability = Reachability()
hostNameLabel.text = "No host name"
}
self.reachability = reachability
print("--- set up with host name: (hostNameLabel.text!)")
if useClosures {
reachability?.whenReachable = { reachability in
self.updateLabelColourWhenReachable(reachability)
}
reachability?.whenUnreachable = { reachability in
self.updateLabelColourWhenNotReachable(reachability)
}
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged(_:)),
name: .reachabilityChanged,
object: reachability
)
}
}
func startNotifier() {
print("--- start notifier")
do {
try reachability?.startNotifier()
} catch {
networkStatus.textColor = .red
networkStatus.text = "Unable to startnnotifier"
return
}
}
func stopNotifier() {
print("--- stop notifier")
reachability?.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: nil)
reachability = nil
}
func updateLabelColourWhenReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
if reachability.connection == .wifi {
self.networkStatus.textColor = .green
} else {
self.networkStatus.textColor = .blue
}
self.networkStatus.text = "(reachability.connection)"
}
func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
self.networkStatus.textColor = .red
self.networkStatus.text = "(reachability.connection)"
}
@objc func reachabilityChanged(_ note: Notification) {
let reachability = note.object as! Reachability
if reachability.connection != .none {
updateLabelColourWhenReachable(reachability)
} else {
updateLabelColourWhenNotReachable(reachability)
}
}
func setConstraints(){
view.addSubview(networkStatus)
view.addSubview(hostNameLabel)
networkStatus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
networkStatus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
networkStatus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
hostNameLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
hostNameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
hostNameLabel.topAnchor.constraint(equalTo: networkStatus.bottomAnchor, constant: 20).isActive = true
}
deinit {
stopNotifier()
}
}
Create a File named Reachability and add this to it:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name {
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String {
return "(connection)"
}
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return .wifi }
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
if !allowsCellularConnection {
connection = .none
} else {
connection = .cellular
}
}
return connection
}
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
public convenience init?() {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
reachabilitySerialQueue.async {
self.reachabilityChanged()
}
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool {
guard isReachableFlagSet else { return false }
if isConnectionRequiredAndTransientFlagSet {
return false
}
if isRunningOnDevice {
if isOnWWANFlagSet && !reachableOnWWAN {
// We don't want to connect when on cellular connection
return false
}
}
return true
}
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
}
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
// Check we're reachable
guard isReachableFlagSet else { return false }
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return true }
// Check we're NOT on WWAN
return !isOnWWANFlagSet
}
var description: String {
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "(W)(R) (c)(t)(i)(C)(D)(l)(d)"
}
}
fileprivate extension Reachability {
func reachabilityChanged() {
guard previousFlags != flags else { return }
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
}
previousFlags = flags
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return flags.contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return flags.contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return flags.contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return flags.contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return flags.contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return flags.contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return flags.contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return flags.contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
var flags: SCNetworkReachabilityFlags {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) {
print("Returning flags (flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
If you want to use this inside your actual project then change the array of hostNames to:
let hostNames = ["google.com"] // or alibaba.com
// move it to viewWillAppear because the reachability class property gets set to nil in stopNotifier when it runs inside deinit
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startHost(at: 0)
}
// remove the dispatch async timer
func startHost(at index: Int) {
setupReachability(hostNames[index], useClosures: true)
startNotifier()
}
// add everything else that's inside the ViewController File above
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
|
show 4 more comments
I was facing the same issue so with the help of some answers on stackoverflow i created a code that simply hit google.com asynchronously and return true in completion handler if response status is 200.
Code in Swift 4:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
Now you can use it like:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43067753%2fswift-ios-what-to-do-when-there-is-a-wifi-connection-but-no-internet-connection%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can init NetworkReachabilityManagerwith host, for example, google host, because default is 0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
When you start listening reachability manager doing ping to host. If network is available you can cache SSID and ping again when SSID changed.
For case .unknown better put a Notification for unsuccessful.
Example get SSID (it doesn't work in Simulator):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManagerguard let ssid = fetchSSIDInfo() else {return} //save ssid
– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
|
show 9 more comments
You can init NetworkReachabilityManagerwith host, for example, google host, because default is 0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
When you start listening reachability manager doing ping to host. If network is available you can cache SSID and ping again when SSID changed.
For case .unknown better put a Notification for unsuccessful.
Example get SSID (it doesn't work in Simulator):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManagerguard let ssid = fetchSSIDInfo() else {return} //save ssid
– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
|
show 9 more comments
You can init NetworkReachabilityManagerwith host, for example, google host, because default is 0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
When you start listening reachability manager doing ping to host. If network is available you can cache SSID and ping again when SSID changed.
For case .unknown better put a Notification for unsuccessful.
Example get SSID (it doesn't work in Simulator):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
You can init NetworkReachabilityManagerwith host, for example, google host, because default is 0.0.0.0
let reachabilityManager = Alamofire.NetworkReachabilityManager(host: "www.google.com")
When you start listening reachability manager doing ping to host. If network is available you can cache SSID and ping again when SSID changed.
For case .unknown better put a Notification for unsuccessful.
Example get SSID (it doesn't work in Simulator):
func fetchSSIDInfo() -> String? {
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("(rec)" as CFString)
if let unsafeInterfaceData = unsafeInterfaceData as? Dictionary<AnyHashable, Any> {
return unsafeInterfaceData["SSID"] as? String
}
}
}
return nil
}
edited Mar 28 '17 at 12:17
answered Mar 28 '17 at 11:51
DialogueDialogue
263
263
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManagerguard let ssid = fetchSSIDInfo() else {return} //save ssid
– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
|
show 9 more comments
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManagerguard let ssid = fetchSSIDInfo() else {return} //save ssid
– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
thanks I'll try it. How do I cache SSID?
– Lance Samaria
Mar 28 '17 at 12:09
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
added get ssid to answer, for save ssid you can use UserDefaults or your DB or other methods
– Dialogue
Mar 28 '17 at 12:21
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
thanks for the help. Do I add that function to the Reachability class or SomeVC? How do you call it and test with bool? I see it returns an Optional of type String
– Lance Samaria
Mar 28 '17 at 12:34
add fetchSSIDInfo() to NetworkManager
guard let ssid = fetchSSIDInfo() else {return} //save ssid– Dialogue
Mar 28 '17 at 16:29
add fetchSSIDInfo() to NetworkManager
guard let ssid = fetchSSIDInfo() else {return} //save ssid– Dialogue
Mar 28 '17 at 16:29
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
you can check SSID changed before send some request type or by timer if let currentSSID = fetchSSIDInfo(), currentSSID != //saved SSID { //do ping}
– Dialogue
Mar 29 '17 at 6:15
|
show 9 more comments
Here's an answer composed of these 2 solutions:Pavle Mijatovic and Yasin Ugurlu
Make a new class and name it Connection and copy and paste the code below inside of it:
import Foundation
import SystemConfiguration
class Connection {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return isReachable && !needsConnection
}
class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {
// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
completionHandler(false)
return
}
// 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
webAddress = webSiteToPing!
}
guard let url = URL(string: webAddress) else {
completionHandler(false)
print("could not create url from: (webAddress)")
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
if error != nil || response == nil {
completionHandler(false)
} else {
completionHandler(true)
}
})
task.resume()
}
}
In whatever view controller your using it in inside viewDidLoad call it like this:
override func viewDidLoad() {
super.viewDidLoad()
// if in china usewww.apple.com or www.alibaba.com instead
Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: {
(bool) in
if bool{
print("Internet connection is good")
}else{
print("No internet connection can be found")
}
})
}
A couple of things I've found out is this only seems to work once because if a connection is available "Internet connection is good" prints but if I go to airplane mode "No internet connection can be found" doesn't print. It's not actively listening which makes me think I have to hook up to a Notification? The other thing is if your in China then this will not work because google isn't available in China. Maybe a better website to check would be www.apple.com or www.alibaba.com as it seems they're available everywhere.
Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"...
or
Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"...
add a comment |
Here's an answer composed of these 2 solutions:Pavle Mijatovic and Yasin Ugurlu
Make a new class and name it Connection and copy and paste the code below inside of it:
import Foundation
import SystemConfiguration
class Connection {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return isReachable && !needsConnection
}
class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {
// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
completionHandler(false)
return
}
// 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
webAddress = webSiteToPing!
}
guard let url = URL(string: webAddress) else {
completionHandler(false)
print("could not create url from: (webAddress)")
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
if error != nil || response == nil {
completionHandler(false)
} else {
completionHandler(true)
}
})
task.resume()
}
}
In whatever view controller your using it in inside viewDidLoad call it like this:
override func viewDidLoad() {
super.viewDidLoad()
// if in china usewww.apple.com or www.alibaba.com instead
Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: {
(bool) in
if bool{
print("Internet connection is good")
}else{
print("No internet connection can be found")
}
})
}
A couple of things I've found out is this only seems to work once because if a connection is available "Internet connection is good" prints but if I go to airplane mode "No internet connection can be found" doesn't print. It's not actively listening which makes me think I have to hook up to a Notification? The other thing is if your in China then this will not work because google isn't available in China. Maybe a better website to check would be www.apple.com or www.alibaba.com as it seems they're available everywhere.
Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"...
or
Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"...
add a comment |
Here's an answer composed of these 2 solutions:Pavle Mijatovic and Yasin Ugurlu
Make a new class and name it Connection and copy and paste the code below inside of it:
import Foundation
import SystemConfiguration
class Connection {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return isReachable && !needsConnection
}
class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {
// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
completionHandler(false)
return
}
// 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
webAddress = webSiteToPing!
}
guard let url = URL(string: webAddress) else {
completionHandler(false)
print("could not create url from: (webAddress)")
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
if error != nil || response == nil {
completionHandler(false)
} else {
completionHandler(true)
}
})
task.resume()
}
}
In whatever view controller your using it in inside viewDidLoad call it like this:
override func viewDidLoad() {
super.viewDidLoad()
// if in china usewww.apple.com or www.alibaba.com instead
Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: {
(bool) in
if bool{
print("Internet connection is good")
}else{
print("No internet connection can be found")
}
})
}
A couple of things I've found out is this only seems to work once because if a connection is available "Internet connection is good" prints but if I go to airplane mode "No internet connection can be found" doesn't print. It's not actively listening which makes me think I have to hook up to a Notification? The other thing is if your in China then this will not work because google isn't available in China. Maybe a better website to check would be www.apple.com or www.alibaba.com as it seems they're available everywhere.
Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"...
or
Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"...
Here's an answer composed of these 2 solutions:Pavle Mijatovic and Yasin Ugurlu
Make a new class and name it Connection and copy and paste the code below inside of it:
import Foundation
import SystemConfiguration
class Connection {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return isReachable && !needsConnection
}
class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {
// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
completionHandler(false)
return
}
// 2. Check the Internet Connection but possibly use www.apple.com or www.alibaba.com instead of google.com because it's not available in China
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
webAddress = webSiteToPing!
}
guard let url = URL(string: webAddress) else {
completionHandler(false)
print("could not create url from: (webAddress)")
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
if error != nil || response == nil {
completionHandler(false)
} else {
completionHandler(true)
}
})
task.resume()
}
}
In whatever view controller your using it in inside viewDidLoad call it like this:
override func viewDidLoad() {
super.viewDidLoad()
// if in china usewww.apple.com or www.alibaba.com instead
Connection.isInternetAvailable(webSiteToPing: "https://www.google.com", completionHandler: {
(bool) in
if bool{
print("Internet connection is good")
}else{
print("No internet connection can be found")
}
})
}
A couple of things I've found out is this only seems to work once because if a connection is available "Internet connection is good" prints but if I go to airplane mode "No internet connection can be found" doesn't print. It's not actively listening which makes me think I have to hook up to a Notification? The other thing is if your in China then this will not work because google isn't available in China. Maybe a better website to check would be www.apple.com or www.alibaba.com as it seems they're available everywhere.
Connection.isInternetAvailable(webSiteToPing: "https://www.apple.com"...
or
Connection.isInternetAvailable(webSiteToPing: "https://www.alibaba.com"...
edited Feb 23 '18 at 17:24
answered Feb 23 '18 at 15:29
Lance SamariaLance Samaria
2,52921451
2,52921451
add a comment |
add a comment |
I followed this AshleyMills Reachability file and it uses google.com to test for a connection. You can just copy and paste the below inside a new file to test to see how it works. If your using this in China then use alibaba.com because google isn't available in China.
// everywhere outside China
let hostNames = [nil, "google.com", "invalidhost"]
// everywhere including China
let hostNames = [nil, "alibaba.com", "invalidhost"]
When you first launch the app you will see the labels change every 5 seconds because there is an async timer inside: func startHost(at index: Int)
If you want to stop it and take control of everything yourself then comment out this code:
// comment this out to stop the connection from changing
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
//self.startHost(at: (index + 1) % 3)
}
Once you comment that out then you should toggle your phones connection between Wifi, Cellular Connection, and Airplane Mode. The label colors will change from green to blue to red depending on the connection.
Create a new project and add this to the ViewController file:
import UIKit
class ViewController: UIViewController {
let networkStatus: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Status"
label.textAlignment = .center
return label
}()
let hostNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Host"
label.textAlignment = .center
return label
}()
var reachability: Reachability?
let hostNames = [nil, "google.com", "invalidhost"]
var hostIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
startHost(at: 1)
}
func startHost(at index: Int) {
stopNotifier()
setupReachability(hostNames[index], useClosures: true)
startNotifier()
// this loops the connection every 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.startHost(at: (index + 1) % 3)
}
}
func setupReachability(_ hostName: String?, useClosures: Bool) {
let reachability: Reachability?
if let hostName = hostName {
reachability = Reachability(hostname: hostName)
hostNameLabel.text = hostName
} else {
reachability = Reachability()
hostNameLabel.text = "No host name"
}
self.reachability = reachability
print("--- set up with host name: (hostNameLabel.text!)")
if useClosures {
reachability?.whenReachable = { reachability in
self.updateLabelColourWhenReachable(reachability)
}
reachability?.whenUnreachable = { reachability in
self.updateLabelColourWhenNotReachable(reachability)
}
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged(_:)),
name: .reachabilityChanged,
object: reachability
)
}
}
func startNotifier() {
print("--- start notifier")
do {
try reachability?.startNotifier()
} catch {
networkStatus.textColor = .red
networkStatus.text = "Unable to startnnotifier"
return
}
}
func stopNotifier() {
print("--- stop notifier")
reachability?.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: nil)
reachability = nil
}
func updateLabelColourWhenReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
if reachability.connection == .wifi {
self.networkStatus.textColor = .green
} else {
self.networkStatus.textColor = .blue
}
self.networkStatus.text = "(reachability.connection)"
}
func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
self.networkStatus.textColor = .red
self.networkStatus.text = "(reachability.connection)"
}
@objc func reachabilityChanged(_ note: Notification) {
let reachability = note.object as! Reachability
if reachability.connection != .none {
updateLabelColourWhenReachable(reachability)
} else {
updateLabelColourWhenNotReachable(reachability)
}
}
func setConstraints(){
view.addSubview(networkStatus)
view.addSubview(hostNameLabel)
networkStatus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
networkStatus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
networkStatus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
hostNameLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
hostNameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
hostNameLabel.topAnchor.constraint(equalTo: networkStatus.bottomAnchor, constant: 20).isActive = true
}
deinit {
stopNotifier()
}
}
Create a File named Reachability and add this to it:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name {
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String {
return "(connection)"
}
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return .wifi }
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
if !allowsCellularConnection {
connection = .none
} else {
connection = .cellular
}
}
return connection
}
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
public convenience init?() {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
reachabilitySerialQueue.async {
self.reachabilityChanged()
}
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool {
guard isReachableFlagSet else { return false }
if isConnectionRequiredAndTransientFlagSet {
return false
}
if isRunningOnDevice {
if isOnWWANFlagSet && !reachableOnWWAN {
// We don't want to connect when on cellular connection
return false
}
}
return true
}
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
}
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
// Check we're reachable
guard isReachableFlagSet else { return false }
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return true }
// Check we're NOT on WWAN
return !isOnWWANFlagSet
}
var description: String {
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "(W)(R) (c)(t)(i)(C)(D)(l)(d)"
}
}
fileprivate extension Reachability {
func reachabilityChanged() {
guard previousFlags != flags else { return }
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
}
previousFlags = flags
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return flags.contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return flags.contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return flags.contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return flags.contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return flags.contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return flags.contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return flags.contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return flags.contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
var flags: SCNetworkReachabilityFlags {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) {
print("Returning flags (flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
If you want to use this inside your actual project then change the array of hostNames to:
let hostNames = ["google.com"] // or alibaba.com
// move it to viewWillAppear because the reachability class property gets set to nil in stopNotifier when it runs inside deinit
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startHost(at: 0)
}
// remove the dispatch async timer
func startHost(at index: Int) {
setupReachability(hostNames[index], useClosures: true)
startNotifier()
}
// add everything else that's inside the ViewController File above
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
|
show 4 more comments
I followed this AshleyMills Reachability file and it uses google.com to test for a connection. You can just copy and paste the below inside a new file to test to see how it works. If your using this in China then use alibaba.com because google isn't available in China.
// everywhere outside China
let hostNames = [nil, "google.com", "invalidhost"]
// everywhere including China
let hostNames = [nil, "alibaba.com", "invalidhost"]
When you first launch the app you will see the labels change every 5 seconds because there is an async timer inside: func startHost(at index: Int)
If you want to stop it and take control of everything yourself then comment out this code:
// comment this out to stop the connection from changing
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
//self.startHost(at: (index + 1) % 3)
}
Once you comment that out then you should toggle your phones connection between Wifi, Cellular Connection, and Airplane Mode. The label colors will change from green to blue to red depending on the connection.
Create a new project and add this to the ViewController file:
import UIKit
class ViewController: UIViewController {
let networkStatus: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Status"
label.textAlignment = .center
return label
}()
let hostNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Host"
label.textAlignment = .center
return label
}()
var reachability: Reachability?
let hostNames = [nil, "google.com", "invalidhost"]
var hostIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
startHost(at: 1)
}
func startHost(at index: Int) {
stopNotifier()
setupReachability(hostNames[index], useClosures: true)
startNotifier()
// this loops the connection every 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.startHost(at: (index + 1) % 3)
}
}
func setupReachability(_ hostName: String?, useClosures: Bool) {
let reachability: Reachability?
if let hostName = hostName {
reachability = Reachability(hostname: hostName)
hostNameLabel.text = hostName
} else {
reachability = Reachability()
hostNameLabel.text = "No host name"
}
self.reachability = reachability
print("--- set up with host name: (hostNameLabel.text!)")
if useClosures {
reachability?.whenReachable = { reachability in
self.updateLabelColourWhenReachable(reachability)
}
reachability?.whenUnreachable = { reachability in
self.updateLabelColourWhenNotReachable(reachability)
}
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged(_:)),
name: .reachabilityChanged,
object: reachability
)
}
}
func startNotifier() {
print("--- start notifier")
do {
try reachability?.startNotifier()
} catch {
networkStatus.textColor = .red
networkStatus.text = "Unable to startnnotifier"
return
}
}
func stopNotifier() {
print("--- stop notifier")
reachability?.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: nil)
reachability = nil
}
func updateLabelColourWhenReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
if reachability.connection == .wifi {
self.networkStatus.textColor = .green
} else {
self.networkStatus.textColor = .blue
}
self.networkStatus.text = "(reachability.connection)"
}
func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
self.networkStatus.textColor = .red
self.networkStatus.text = "(reachability.connection)"
}
@objc func reachabilityChanged(_ note: Notification) {
let reachability = note.object as! Reachability
if reachability.connection != .none {
updateLabelColourWhenReachable(reachability)
} else {
updateLabelColourWhenNotReachable(reachability)
}
}
func setConstraints(){
view.addSubview(networkStatus)
view.addSubview(hostNameLabel)
networkStatus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
networkStatus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
networkStatus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
hostNameLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
hostNameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
hostNameLabel.topAnchor.constraint(equalTo: networkStatus.bottomAnchor, constant: 20).isActive = true
}
deinit {
stopNotifier()
}
}
Create a File named Reachability and add this to it:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name {
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String {
return "(connection)"
}
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return .wifi }
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
if !allowsCellularConnection {
connection = .none
} else {
connection = .cellular
}
}
return connection
}
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
public convenience init?() {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
reachabilitySerialQueue.async {
self.reachabilityChanged()
}
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool {
guard isReachableFlagSet else { return false }
if isConnectionRequiredAndTransientFlagSet {
return false
}
if isRunningOnDevice {
if isOnWWANFlagSet && !reachableOnWWAN {
// We don't want to connect when on cellular connection
return false
}
}
return true
}
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
}
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
// Check we're reachable
guard isReachableFlagSet else { return false }
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return true }
// Check we're NOT on WWAN
return !isOnWWANFlagSet
}
var description: String {
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "(W)(R) (c)(t)(i)(C)(D)(l)(d)"
}
}
fileprivate extension Reachability {
func reachabilityChanged() {
guard previousFlags != flags else { return }
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
}
previousFlags = flags
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return flags.contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return flags.contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return flags.contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return flags.contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return flags.contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return flags.contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return flags.contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return flags.contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
var flags: SCNetworkReachabilityFlags {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) {
print("Returning flags (flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
If you want to use this inside your actual project then change the array of hostNames to:
let hostNames = ["google.com"] // or alibaba.com
// move it to viewWillAppear because the reachability class property gets set to nil in stopNotifier when it runs inside deinit
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startHost(at: 0)
}
// remove the dispatch async timer
func startHost(at index: Int) {
setupReachability(hostNames[index], useClosures: true)
startNotifier()
}
// add everything else that's inside the ViewController File above
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
|
show 4 more comments
I followed this AshleyMills Reachability file and it uses google.com to test for a connection. You can just copy and paste the below inside a new file to test to see how it works. If your using this in China then use alibaba.com because google isn't available in China.
// everywhere outside China
let hostNames = [nil, "google.com", "invalidhost"]
// everywhere including China
let hostNames = [nil, "alibaba.com", "invalidhost"]
When you first launch the app you will see the labels change every 5 seconds because there is an async timer inside: func startHost(at index: Int)
If you want to stop it and take control of everything yourself then comment out this code:
// comment this out to stop the connection from changing
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
//self.startHost(at: (index + 1) % 3)
}
Once you comment that out then you should toggle your phones connection between Wifi, Cellular Connection, and Airplane Mode. The label colors will change from green to blue to red depending on the connection.
Create a new project and add this to the ViewController file:
import UIKit
class ViewController: UIViewController {
let networkStatus: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Status"
label.textAlignment = .center
return label
}()
let hostNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Host"
label.textAlignment = .center
return label
}()
var reachability: Reachability?
let hostNames = [nil, "google.com", "invalidhost"]
var hostIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
startHost(at: 1)
}
func startHost(at index: Int) {
stopNotifier()
setupReachability(hostNames[index], useClosures: true)
startNotifier()
// this loops the connection every 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.startHost(at: (index + 1) % 3)
}
}
func setupReachability(_ hostName: String?, useClosures: Bool) {
let reachability: Reachability?
if let hostName = hostName {
reachability = Reachability(hostname: hostName)
hostNameLabel.text = hostName
} else {
reachability = Reachability()
hostNameLabel.text = "No host name"
}
self.reachability = reachability
print("--- set up with host name: (hostNameLabel.text!)")
if useClosures {
reachability?.whenReachable = { reachability in
self.updateLabelColourWhenReachable(reachability)
}
reachability?.whenUnreachable = { reachability in
self.updateLabelColourWhenNotReachable(reachability)
}
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged(_:)),
name: .reachabilityChanged,
object: reachability
)
}
}
func startNotifier() {
print("--- start notifier")
do {
try reachability?.startNotifier()
} catch {
networkStatus.textColor = .red
networkStatus.text = "Unable to startnnotifier"
return
}
}
func stopNotifier() {
print("--- stop notifier")
reachability?.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: nil)
reachability = nil
}
func updateLabelColourWhenReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
if reachability.connection == .wifi {
self.networkStatus.textColor = .green
} else {
self.networkStatus.textColor = .blue
}
self.networkStatus.text = "(reachability.connection)"
}
func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
self.networkStatus.textColor = .red
self.networkStatus.text = "(reachability.connection)"
}
@objc func reachabilityChanged(_ note: Notification) {
let reachability = note.object as! Reachability
if reachability.connection != .none {
updateLabelColourWhenReachable(reachability)
} else {
updateLabelColourWhenNotReachable(reachability)
}
}
func setConstraints(){
view.addSubview(networkStatus)
view.addSubview(hostNameLabel)
networkStatus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
networkStatus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
networkStatus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
hostNameLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
hostNameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
hostNameLabel.topAnchor.constraint(equalTo: networkStatus.bottomAnchor, constant: 20).isActive = true
}
deinit {
stopNotifier()
}
}
Create a File named Reachability and add this to it:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name {
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String {
return "(connection)"
}
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return .wifi }
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
if !allowsCellularConnection {
connection = .none
} else {
connection = .cellular
}
}
return connection
}
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
public convenience init?() {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
reachabilitySerialQueue.async {
self.reachabilityChanged()
}
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool {
guard isReachableFlagSet else { return false }
if isConnectionRequiredAndTransientFlagSet {
return false
}
if isRunningOnDevice {
if isOnWWANFlagSet && !reachableOnWWAN {
// We don't want to connect when on cellular connection
return false
}
}
return true
}
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
}
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
// Check we're reachable
guard isReachableFlagSet else { return false }
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return true }
// Check we're NOT on WWAN
return !isOnWWANFlagSet
}
var description: String {
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "(W)(R) (c)(t)(i)(C)(D)(l)(d)"
}
}
fileprivate extension Reachability {
func reachabilityChanged() {
guard previousFlags != flags else { return }
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
}
previousFlags = flags
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return flags.contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return flags.contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return flags.contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return flags.contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return flags.contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return flags.contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return flags.contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return flags.contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
var flags: SCNetworkReachabilityFlags {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) {
print("Returning flags (flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
If you want to use this inside your actual project then change the array of hostNames to:
let hostNames = ["google.com"] // or alibaba.com
// move it to viewWillAppear because the reachability class property gets set to nil in stopNotifier when it runs inside deinit
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startHost(at: 0)
}
// remove the dispatch async timer
func startHost(at index: Int) {
setupReachability(hostNames[index], useClosures: true)
startNotifier()
}
// add everything else that's inside the ViewController File above
I followed this AshleyMills Reachability file and it uses google.com to test for a connection. You can just copy and paste the below inside a new file to test to see how it works. If your using this in China then use alibaba.com because google isn't available in China.
// everywhere outside China
let hostNames = [nil, "google.com", "invalidhost"]
// everywhere including China
let hostNames = [nil, "alibaba.com", "invalidhost"]
When you first launch the app you will see the labels change every 5 seconds because there is an async timer inside: func startHost(at index: Int)
If you want to stop it and take control of everything yourself then comment out this code:
// comment this out to stop the connection from changing
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
//self.startHost(at: (index + 1) % 3)
}
Once you comment that out then you should toggle your phones connection between Wifi, Cellular Connection, and Airplane Mode. The label colors will change from green to blue to red depending on the connection.
Create a new project and add this to the ViewController file:
import UIKit
class ViewController: UIViewController {
let networkStatus: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Status"
label.textAlignment = .center
return label
}()
let hostNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = .black
label.numberOfLines = 0
label.sizeToFit()
label.text = "Host"
label.textAlignment = .center
return label
}()
var reachability: Reachability?
let hostNames = [nil, "google.com", "invalidhost"]
var hostIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
startHost(at: 1)
}
func startHost(at index: Int) {
stopNotifier()
setupReachability(hostNames[index], useClosures: true)
startNotifier()
// this loops the connection every 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.startHost(at: (index + 1) % 3)
}
}
func setupReachability(_ hostName: String?, useClosures: Bool) {
let reachability: Reachability?
if let hostName = hostName {
reachability = Reachability(hostname: hostName)
hostNameLabel.text = hostName
} else {
reachability = Reachability()
hostNameLabel.text = "No host name"
}
self.reachability = reachability
print("--- set up with host name: (hostNameLabel.text!)")
if useClosures {
reachability?.whenReachable = { reachability in
self.updateLabelColourWhenReachable(reachability)
}
reachability?.whenUnreachable = { reachability in
self.updateLabelColourWhenNotReachable(reachability)
}
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged(_:)),
name: .reachabilityChanged,
object: reachability
)
}
}
func startNotifier() {
print("--- start notifier")
do {
try reachability?.startNotifier()
} catch {
networkStatus.textColor = .red
networkStatus.text = "Unable to startnnotifier"
return
}
}
func stopNotifier() {
print("--- stop notifier")
reachability?.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: nil)
reachability = nil
}
func updateLabelColourWhenReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
if reachability.connection == .wifi {
self.networkStatus.textColor = .green
} else {
self.networkStatus.textColor = .blue
}
self.networkStatus.text = "(reachability.connection)"
}
func updateLabelColourWhenNotReachable(_ reachability: Reachability) {
print("(reachability.description) - (reachability.connection)")
self.networkStatus.textColor = .red
self.networkStatus.text = "(reachability.connection)"
}
@objc func reachabilityChanged(_ note: Notification) {
let reachability = note.object as! Reachability
if reachability.connection != .none {
updateLabelColourWhenReachable(reachability)
} else {
updateLabelColourWhenNotReachable(reachability)
}
}
func setConstraints(){
view.addSubview(networkStatus)
view.addSubview(hostNameLabel)
networkStatus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
networkStatus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
networkStatus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
hostNameLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
hostNameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
hostNameLabel.topAnchor.constraint(equalTo: networkStatus.bottomAnchor, constant: 20).isActive = true
}
deinit {
stopNotifier()
}
}
Create a File named Reachability and add this to it:
import SystemConfiguration
import Foundation
public enum ReachabilityError: Error {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")
extension Notification.Name {
public static let reachabilityChanged = Notification.Name("reachabilityChanged")
}
func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
let reachability = Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue()
reachability.reachabilityChanged()
}
public class Reachability {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
@available(*, unavailable, renamed: "Connection")
public enum NetworkStatus: CustomStringConvertible {
case notReachable, reachableViaWiFi, reachableViaWWAN
public var description: String {
switch self {
case .reachableViaWWAN: return "Cellular"
case .reachableViaWiFi: return "WiFi"
case .notReachable: return "No Connection"
}
}
}
public enum Connection: CustomStringConvertible {
case none, wifi, cellular
public var description: String {
switch self {
case .cellular: return "Cellular"
case .wifi: return "WiFi"
case .none: return "No Connection"
}
}
}
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
@available(*, deprecated: 4.0, renamed: "allowsCellularConnection")
public let reachableOnWWAN: Bool = true
/// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`)
public var allowsCellularConnection: Bool
// The notification center on which "reachability changed" events are being posted
public var notificationCenter: NotificationCenter = NotificationCenter.default
@available(*, deprecated: 4.0, renamed: "connection.description")
public var currentReachabilityString: String {
return "(connection)"
}
@available(*, unavailable, renamed: "connection")
public var currentReachabilityStatus: Connection {
return connection
}
public var connection: Connection {
guard isReachableFlagSet else { return .none }
// If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return .wifi }
var connection = Connection.none
if !isConnectionRequiredFlagSet {
connection = .wifi
}
if isConnectionOnTrafficOrDemandFlagSet {
if !isInterventionRequiredFlagSet {
connection = .wifi
}
}
if isOnWWANFlagSet {
if !allowsCellularConnection {
connection = .none
} else {
connection = .cellular
}
}
return connection
}
fileprivate var previousFlags: SCNetworkReachabilityFlags?
fileprivate var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
fileprivate var notifierRunning = false
fileprivate let reachabilityRef: SCNetworkReachability
fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability")
fileprivate var usingHostname = false
required public init(reachabilityRef: SCNetworkReachability, usingHostname: Bool = false) {
allowsCellularConnection = true
self.reachabilityRef = reachabilityRef
self.usingHostname = usingHostname
}
public convenience init?(hostname: String) {
guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
self.init(reachabilityRef: ref, usingHostname: true)
}
public convenience init?() {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil }
self.init(reachabilityRef: ref)
}
deinit {
stopNotifier()
}
}
public extension Reachability {
// MARK: - *** Notifier methods ***
func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an initial check
reachabilitySerialQueue.async {
self.reachabilityChanged()
}
notifierRunning = true
}
func stopNotifier() {
defer { notifierRunning = false }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
@available(*, deprecated: 4.0, message: "Please use `connection != .none`")
var isReachable: Bool {
guard isReachableFlagSet else { return false }
if isConnectionRequiredAndTransientFlagSet {
return false
}
if isRunningOnDevice {
if isOnWWANFlagSet && !reachableOnWWAN {
// We don't want to connect when on cellular connection
return false
}
}
return true
}
@available(*, deprecated: 4.0, message: "Please use `connection == .cellular`")
var isReachableViaWWAN: Bool {
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet
}
@available(*, deprecated: 4.0, message: "Please use `connection == .wifi`")
var isReachableViaWiFi: Bool {
// Check we're reachable
guard isReachableFlagSet else { return false }
// If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi
guard isRunningOnDevice else { return true }
// Check we're NOT on WWAN
return !isOnWWANFlagSet
}
var description: String {
let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X"
let R = isReachableFlagSet ? "R" : "-"
let c = isConnectionRequiredFlagSet ? "c" : "-"
let t = isTransientConnectionFlagSet ? "t" : "-"
let i = isInterventionRequiredFlagSet ? "i" : "-"
let C = isConnectionOnTrafficFlagSet ? "C" : "-"
let D = isConnectionOnDemandFlagSet ? "D" : "-"
let l = isLocalAddressFlagSet ? "l" : "-"
let d = isDirectFlagSet ? "d" : "-"
return "(W)(R) (c)(t)(i)(C)(D)(l)(d)"
}
}
fileprivate extension Reachability {
func reachabilityChanged() {
guard previousFlags != flags else { return }
let block = connection != .none ? whenReachable : whenUnreachable
DispatchQueue.main.async {
if self.usingHostname {
print("USING HOSTNAME ABOUT TO CALL BLOCK")
}
block?(self)
self.notificationCenter.post(name: .reachabilityChanged, object:self)
}
previousFlags = flags
}
var isOnWWANFlagSet: Bool {
#if os(iOS)
return flags.contains(.isWWAN)
#else
return false
#endif
}
var isReachableFlagSet: Bool {
return flags.contains(.reachable)
}
var isConnectionRequiredFlagSet: Bool {
return flags.contains(.connectionRequired)
}
var isInterventionRequiredFlagSet: Bool {
return flags.contains(.interventionRequired)
}
var isConnectionOnTrafficFlagSet: Bool {
return flags.contains(.connectionOnTraffic)
}
var isConnectionOnDemandFlagSet: Bool {
return flags.contains(.connectionOnDemand)
}
var isConnectionOnTrafficOrDemandFlagSet: Bool {
return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty
}
var isTransientConnectionFlagSet: Bool {
return flags.contains(.transientConnection)
}
var isLocalAddressFlagSet: Bool {
return flags.contains(.isLocalAddress)
}
var isDirectFlagSet: Bool {
return flags.contains(.isDirect)
}
var isConnectionRequiredAndTransientFlagSet: Bool {
return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
}
var flags: SCNetworkReachabilityFlags {
var flags = SCNetworkReachabilityFlags()
if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) {
print("Returning flags (flags)")
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
}
If you want to use this inside your actual project then change the array of hostNames to:
let hostNames = ["google.com"] // or alibaba.com
// move it to viewWillAppear because the reachability class property gets set to nil in stopNotifier when it runs inside deinit
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startHost(at: 0)
}
// remove the dispatch async timer
func startHost(at index: Int) {
setupReachability(hostNames[index], useClosures: true)
startNotifier()
}
// add everything else that's inside the ViewController File above
edited May 13 '18 at 15:34
answered Oct 11 '17 at 15:18
Lance SamariaLance Samaria
2,52921451
2,52921451
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
|
show 4 more comments
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
Lance thanks for trying to help. I would like some clarification, especially because i think that none of the answers actually answer your question. Your use case is: "For e.g.. if I have a wifi router and it's plugged in but the router isn't connected to the internet Alamofire will view this as a successful connection because it actually is connecting to wifi although it doesn't know the wifi can't connect to the internet." This is what you've stated, and if you try the code from youtube link and change Alamofire with Reachability, it doesn't answer the question.
– IvanMih
Oct 12 '17 at 8:15
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih I haven't had any problems with the code from the YouTube video. I've connected to wifi, received no data, and the Ashly Mills reachability showed no connection. Is the YouTube code not working in the way I just described? As for the accepted answer, the reason I picked it was because he was correct in saying connect to a site like google that is guaranteed to always be reachable, if not, then there's a problem. His explanation of how to use it wasn't clear but he was correct.
– Lance Samaria
Oct 12 '17 at 10:56
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
@IvanMih Ivan I did some googling around, check this answer. I'm in the US and what I didn't realize or think about is if you try to ping google in countries that don't support it like China then it won't work. Also if your on 2G there may be an issue. stackoverflow.com/questions/24516748/… . I'll do more research into the different answers and get back to to you. If you find something more concrete let me know, post the answer, and I'll upvote you. If I find it I'll post it for you
– Lance Samaria
Oct 12 '17 at 11:13
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
one thing between our tests could be different: I was using another phone's hotspot and turned mobile data on and off on that other phone. Later i'll try with a router. I really don't think there should be any difference in the outcome, but who knows. I've made a test project with reachability test + simple ping test (another approach in solving this problem). If you'd like to take a look, and correct me if you see some mistakes: github.com/ivanmih/NetworkTest. And i'm in Europe so i have access to google.
– IvanMih
Oct 12 '17 at 13:01
1
1
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
@IvanMih I'm going to an iOS meetup next Wed. There are experts there. I'm not sure how fast you need an answer but I should be able to get some on hands help there.
– Lance Samaria
Oct 12 '17 at 20:32
|
show 4 more comments
I was facing the same issue so with the help of some answers on stackoverflow i created a code that simply hit google.com asynchronously and return true in completion handler if response status is 200.
Code in Swift 4:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
Now you can use it like:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
add a comment |
I was facing the same issue so with the help of some answers on stackoverflow i created a code that simply hit google.com asynchronously and return true in completion handler if response status is 200.
Code in Swift 4:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
Now you can use it like:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
add a comment |
I was facing the same issue so with the help of some answers on stackoverflow i created a code that simply hit google.com asynchronously and return true in completion handler if response status is 200.
Code in Swift 4:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
Now you can use it like:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
I was facing the same issue so with the help of some answers on stackoverflow i created a code that simply hit google.com asynchronously and return true in completion handler if response status is 200.
Code in Swift 4:
class func checkInternet(showLoader: Bool = true, completionHandler:@escaping (_ internet:Bool) -> Void)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let url = URL(string: "http://www.google.com/")
var req = URLRequest.init(url: url!)
req.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
req.timeoutInterval = 10.0
if showLoader {
Loader.startLoading()
}
let task = URLSession.shared.dataTask(with: req) { (data, response, error) in
if showLoader {
Loader.stopLoading()
}
if error != nil {
completionHandler(false)
} else {
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
} else {
completionHandler(false)
}
} else {
completionHandler(false)
}
}
}
task.resume()
}
Now you can use it like:
InternetCheck.checkInternet(completionHandler: { (available) in
if available {
print("Net available")
} else {
print("Net not available")
}
edited Jan 9 at 7:34
answered Jan 1 at 5:10
Ammar MujeebAmmar Mujeeb
6071017
6071017
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
add a comment |
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
you should post an example on how to use it
– Lance Samaria
Jan 4 at 20:13
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
added usage example code.
– Ammar Mujeeb
Jan 9 at 7:36
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
cool thanks for adding it 😊
– Lance Samaria
Jan 9 at 7:37
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43067753%2fswift-ios-what-to-do-when-there-is-a-wifi-connection-but-no-internet-connection%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
