5


I state that I am new to Swift and iOS in general.
I'd like to understand (in viewDidLoad) how I can check if the iPhone is connected to the internet, instantly, at that moment!
The new NWPathMonitor() class seems to be useful only for managing connection changes, but not for instantaneously checking the connection.

My ViewController

import UIKit
import WebKit
import Network

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

    // Status bar black characters
    override var preferredStatusBarStyle: UIStatusBarStyle { return .darkContent }
    // La nostra webview
    var webView: WKWebView!
    // NETWORK MONITORING
    let monitor = NWPathMonitor()
    let queue = DispatchQueue(label: "InternetConnectionMonitor")
    var internetConnected = false

    // 1 - Eseguita durante il caricamento della view
    override func loadView() {
        super.loadView()

        // WEB VIEW
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView

        // NETWORK MONITORING
        monitor.pathUpdateHandler = { path in
            if path.status == .satisfied {
                print("dedalos-print INTERNET OK 1")
                if (!self.internetConnected) {
                    self.internetConnected = true
                    self.loadWebView()
                }
            }
            else {
                print("dedalos-print NO INTERNET 1")
                self.internetConnected = false
                self.loadHTMLerror()
            }
        }

        monitor.start(queue: queue)

    }

    // 2 - Eseguita dopo il caricamento della view
    override func viewDidLoad() {
        super.viewDidLoad()

        if (self.internetConnected) {
            print("dedalos-print INTERNET OK 2")
            self.loadWebView()
        }
        else {
            print("dedalos-print NO INTERNET 2")
        }

    }

    // 3 - Eseguita poco prima di mostrarsi
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    // 4 - Eseguita dopo essersi mostrata
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }


}

Thanks in advance!

3

5 Answers 5

7

If you don't want to use a third party library.

Create NetworkCheck class :

import Network

protocol NetworkCheckObserver: class {
    func statusDidChange(status: NWPath.Status)
}

class NetworkCheck {

    struct NetworkChangeObservation {
        weak var observer: NetworkCheckObserver?
    }

    private var monitor = NWPathMonitor()
    private static let _sharedInstance = NetworkCheck()
    private var observations = [ObjectIdentifier: NetworkChangeObservation]()
    var currentStatus: NWPath.Status {
        get {
            return monitor.currentPath.status
        }
    }

    class func sharedInstance() -> NetworkCheck {
        return _sharedInstance
    }

    init() {
        monitor.pathUpdateHandler = { [unowned self] path in
            for (id, observations) in self.observations {

                //If any observer is nil, remove it from the list of observers
                guard let observer = observations.observer else {
                    self.observations.removeValue(forKey: id)
                    continue
                }

                DispatchQueue.main.async(execute: {
                    observer.statusDidChange(status: path.status)
                })
            }
        }
        monitor.start(queue: DispatchQueue.global(qos: .background))
    }

    func addObserver(observer: NetworkCheckObserver) {
        let id = ObjectIdentifier(observer)
        observations[id] = NetworkChangeObservation(observer: observer)
    }

    func removeObserver(observer: NetworkCheckObserver) {
        let id = ObjectIdentifier(observer)
        observations.removeValue(forKey: id)
    }

}

Then in your ViewController you can check for network changes.

    import Network

 class ViewController: UIViewController,NetworkCheckObserver {

    var networkCheck = NetworkCheck.sharedInstance()

    override func viewDidLoad() {
            super.viewDidLoad()

            if networkCheck.currentStatus == .satisfied{
                //Do something
            }else{
                //Show no network alert
            }
            networkCheck.addObserver(observer: self)
    }

    func statusDidChange(status: NWPath.Status) {
        if status == .satisfied {
            //Do something
        }else if status == .unsatisfied {
            //Show no network alert
        }
    }
    }
Sign up to request clarification or add additional context in comments.

2 Comments

I was testing this solution, but it fails in this scenario, put your simulator to a wifi network then in your mac turn Wi-Fi Off you get status == .unsatisfied that's good but if you turn Wi-Fi On again then you get again status == .unsatisfied and the status == .satisfied never arrived.
from what I read NWPathMonitor is flaky with the simulator which is really a shame and a poor move on Apple's part.
1

The closest thing you can use is the new Concurrency framework.

With a simple async await function you can get a a single point in time.

Task{
    internetConnected = await ConnectionService.isConnected()
    //This line won't run until the result is available
}

or you can use an AsyncStream to do continuous monitoring.

Task{
    for await status in ConnectionService.monitorNetwork(){
        internetConnected = status
        //This line would run every time there is an update
    }
}

Here is what the ConnectionService would look like.

import Foundation
import Network

actor ConnectionService {
    /// Continuos monitoring of network
    static func monitorNetwork() -> AsyncStream<Bool>{
        AsyncStream { continuation in
            let monitor = NWPathMonitor()

            monitor.pathUpdateHandler = { path in
                switch path.status {
                case .satisfied:
                    continuation.yield(true)
                case .unsatisfied, .requiresConnection:
                    continuation.yield(false)
                @unknown default:
                    continuation.yield(false)
                }
            }

            monitor.start(queue: DispatchQueue(label: "InternetConnectionMonitor"))
            
            continuation.onTermination = { _ in
                monitor.cancel()
            }
        }
    }
    ///Returns a single value
    static func isConnected() async -> Bool{
        typealias Continuation = CheckedContinuation<Bool, Never>
        return await withCheckedContinuation({ (continuation: Continuation) in
            let monitor = NWPathMonitor()

            monitor.pathUpdateHandler = { path in
                monitor.cancel()
                switch path.status {
                case .satisfied:
                    continuation.resume(returning: true)
                case .unsatisfied, .requiresConnection:
                    continuation.resume(returning: false)
                @unknown default:
                    continuation.resume(returning: false)
                }
            }
            monitor.start(queue: DispatchQueue(label: "InternetConnectionMonitor"))
        })
    }
}

This solution works with both SwiftUI and UIKit.

1 Comment

This is really nice, but I don't think you need to make ConnectionService an actor since it doesn't protect any isolated state (properties).
0

Try Reachability from Apple. It will directly get connectivity status to you.

guard let r = Reachability("https://www.apple.com") else { return }

if r.connectionRequired() {
    // connection required
    return
}

switch r.currentReachabilityStatus() {
case NotReachable:
    // Not Reachable
    break
case ReachableViaWWAN, ReachableViaWiFi:
    // Reachable!!
    break
default:
    break
}

2 Comments

Ah ok, thank you very much! But I think will be deprecated... medium.com/@rwbutler/…
@Stefano It won't. Reachability class from Apple is using APIs from SystemConfiguration framework. It won't be deprecated for the next few years I guess. NWPathMonitor is just kinda modern way to detect connectivity.
0

You can also just see if you can resolve a location with getaddrinfo

#if os(macOS)
import Cocoa
#else
import Foundation
#endif

func reachable(host: String) -> Bool {
    var res: UnsafeMutablePointer<addrinfo>?
    let n = getaddrinfo(host, nil, nil, &res)
    freeaddrinfo(res)
    return n == 0
}
var isConnectedToInternet: Bool { reachable(host: "apple.com") }

print("Connected to internet: \(isConnectedToInternet)")

Comments

0

Swift Code :

Try this code for check internet connection instantly.

import Foundation
import SystemConfiguration

class NetworkManager: NSObject {

    static let sharedInstance: NetworkManager = { return NetworkManager() }()
    
    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)
        
        let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
                SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
            }
        }
        var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
            return false
        }
        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)
        let ret = (isReachable && !needsConnection)
        
        return ret
    }
    
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.