Check for internet connection with Swift

前端 未结 21 1548
别跟我提以往
别跟我提以往 2020-11-22 05:59

When I try to check for an internet connection on my iPhone I get a bunch of errors. Can anyone help me to fix this?

The code:

import Foundation
impo         


        
相关标签:
21条回答
  • 2020-11-22 06:05

    If someone is already using Alamofire then -

    struct Connectivity {
      static let sharedInstance = NetworkReachabilityManager()!
      static var isConnectedToInternet:Bool {
          return self.sharedInstance.isReachable
        }
    }
    

    Usage:

    if Connectivity.isConnectedToInternet {
         print("Connected")
     } else {
         print("No Internet")
    }
    
    0 讨论(0)
  • 2020-11-22 06:05

    I have checked out implementing Ashley Mill's Reachability class without Cocoa Pods/Dependancy Manager. The idea is to make the Reachability dependency free in the project.

    Xcode 7.2 - Swift 2.1

    1) https://github.com/ashleymills/Reachability.swift. Download add the Reachability class to the project .

    Note: While adding, please make sure 'copy items if needed' is ticked.

    2) Make an AppManager.swift class . This class will cater as Public Model class where public methods & data will be added and can be utilised in any VC.

    //  AppManager.swift
    
    import UIKit
    import Foundation
    
    class AppManager: NSObject{
        var delegate:AppManagerDelegate? = nil
        private var _useClosures:Bool = false
        private var reachability: Reachability?
        private var _isReachability:Bool = false
        private var _reachabiltyNetworkType :String?
    
        var isReachability:Bool {
            get {return _isReachability}
        }  
       var reachabiltyNetworkType:String {
        get {return _reachabiltyNetworkType! }
       }   
    
    
    
    
        // Create a shared instance of AppManager
        final  class var sharedInstance : AppManager {
            struct Static {
                static var instance : AppManager?
            }
            if !(Static.instance != nil) {
                Static.instance = AppManager()
    
            }
            return Static.instance!
        }
    
        // Reachability Methods
        func initRechabilityMonitor() {
            print("initialize rechability...")
            do {
                let reachability = try Reachability.reachabilityForInternetConnection()
                self.reachability = reachability
            } catch ReachabilityError.FailedToCreateWithAddress(let address) {
                print("Unable to create\nReachability with address:\n\(address)")
                return
            } catch {}
            if (_useClosures) {
                reachability?.whenReachable = { reachability in
                    self.notifyReachability(reachability)
                }
                reachability?.whenUnreachable = { reachability in
                    self.notifyReachability(reachability)
                }
            } else {
                self.notifyReachability(reachability!)
            }
    
            do {
                try reachability?.startNotifier()
            } catch {
                print("unable to start notifier")
                return
            }
    
    
        }        
        private func notifyReachability(reachability:Reachability) {
            if reachability.isReachable() {
                self._isReachability = true
    
    //Determine Network Type 
          if reachability.isReachableViaWiFi() {   
            self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WIFI_NETWORK.rawValue
          } else {
            self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WWAN_NETWORK.rawValue
          }
    
            } else {
                self._isReachability = false
    self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.OTHER.rawValue
    
            }
    
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: ReachabilityChangedNotification, object: reachability)
        }
        func reachabilityChanged(note: NSNotification) {
            let reachability = note.object as! Reachability
            dispatch_async(dispatch_get_main_queue()) {
                if (self._useClosures) {
                    self.reachability?.whenReachable = { reachability in
                        self.notifyReachability(reachability)
                    }
                    self.reachability?.whenUnreachable = { reachability in
                        self.notifyReachability(reachability)
                    }
                } else {
                    self.notifyReachability(reachability)
                }
                self.delegate?.reachabilityStatusChangeHandler(reachability)
            }
        }
        deinit {
            reachability?.stopNotifier()
            if (!_useClosures) {
                NSNotificationCenter.defaultCenter().removeObserver(self, name: ReachabilityChangedNotification, object: nil)
            }
        }
    }
    

    3) Make a Delegate Class. I use delegate method to notify the connectivity status.

    //  Protocols.swift
    
    import Foundation
    @objc protocol AppManagerDelegate:NSObjectProtocol {
    
        func reachabilityStatusChangeHandler(reachability:Reachability)
    }
    

    4) Make Parent class of UIViewController (Inheritance method). The parent class have methods which are accessible all child VCs.

    //  UIappViewController.swift
    
        import UIKit
    
        class UIappViewController: UIViewController,AppManagerDelegate {
            var manager:AppManager = AppManager.sharedInstance
    
            override func viewDidLoad() {
                super.viewDidLoad()
                manager.delegate = self
            }
            override func didReceiveMemoryWarning() {
                super.didReceiveMemoryWarning()
            }
            func reachabilityStatusChangeHandler(reachability: Reachability) {
                if reachability.isReachable() {
                    print("isReachable")
                } else {
                    print("notReachable")
                }
            }
        }
    

    5) Start Real time Internet Connectivity Monitoring in AppDelegate.

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        AppManager.sharedInstance.initRechabilityMonitor()
    return true
    }
    

    6) I have added a Swift File Name AppReference to store constant enum values.

    //  AppReference.swift
    
    import Foundation
    
    enum CONNECTION_NETWORK_TYPE : String {
    
      case WIFI_NETWORK = "Wifi"
      case WWAN_NETWORK = "Cellular"
      case OTHER = "Other"
    
    }
    

    7) On ViewController (ex. You want to call an API only if network is available)

    //  ViewController.swift
    
            import UIKit
    
    class ViewController: UIappViewController {
      var reachability:Reachability?
    
      override func viewDidLoad() {
        super.viewDidLoad()
        manager.delegate = self
    
        if(AppManager.sharedInstance.isReachability)
        {
          print("net available")
          //call API from here.
    
        } else {
          dispatch_async(dispatch_get_main_queue()) {
            print("net not available")
            //Show Alert
          }
        }
    
    
        //Determine Network Type
        if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
        {
          print(".Wifi")
        }
        else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
        {
          print(".Cellular")
        }
        else {
          dispatch_async(dispatch_get_main_queue()) {
            print("Network not reachable")
          }
        }
    
      }
      override func viewWillAppear(animated: Bool) {
      }
      override func didReceiveMemoryWarning() {
      }
    }
    

    The sample can be downloaded @ https://github.com/alvinreuben/Reachability-Sample

    Upgraded to Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3

    0 讨论(0)
  • 2020-11-22 06:07

    Create a new Swift file within your project, name it Reachability.swift. Cut & paste the following code into it to create your class.

    import Foundation
    import SystemConfiguration
    
    public class Reachability {
    
        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(sizeofValue(zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)
    
            let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
                SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0))
            }
    
            var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
            if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
                 return false
            }
    
            let isReachable = flags == .Reachable
            let needsConnection = flags == .ConnectionRequired
    
            return isReachable && !needsConnection
    
        }
    }
    

    You can check internet connection anywhere in your project using this code:

    if Reachability.isConnectedToNetwork() {
        println("Internet connection OK")
    } else {
        println("Internet connection FAILED")
    }
    

    If the user is not connected to the internet, you may want to show them an alert dialog to notify them.

    if Reachability.isConnectedToNetwork() {
        println("Internet connection OK")
    } else {
        println("Internet connection FAILED")
        var alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
        alert.show()
    }
    

    Explanation:

    We are making a reusable public class and a method which can be used anywhere in the project to check internet connectivity. We require adding Foundation and System Configuration frameworks.

    In the public class Reachability, the method isConnectedToNetwork() -> Bool { } will return a bool value about internet connectivity. We use a if loop to perform required actions on case. I hope this is enough. Cheers!

    0 讨论(0)
  • 2020-11-22 06:08

    Apple has introduced Network Framework in iOS12.

    import Foundation
    import Network
    
    class NetworkReachability {
    
       var pathMonitor: NWPathMonitor!
       var path: NWPath?
       lazy var pathUpdateHandler: ((NWPath) -> Void) = { path in
        self.path = path
        if path.status == NWPath.Status.satisfied {
            print("Connected")
        } else if path.status == NWPath.Status.unsatisfied {
            print("unsatisfied")
        } else if path.status == NWPath.Status.requiresConnection {
            print("requiresConnection")
        } 
    }
    
    let backgroudQueue = DispatchQueue.global(qos: .background)
    
    init() {
        pathMonitor = NWPathMonitor()
        pathMonitor.pathUpdateHandler = self.pathUpdateHandler
        pathMonitor.start(queue: backgroudQueue)
       } 
    
     func isNetworkAvailable() -> Bool {
            if let path = self.path {
               if path.status == NWPath.Status.satisfied {
                return true
              }
            }
           return false
       }
     }
    
    0 讨论(0)
  • 2020-11-22 06:08

    iOS12 Swift 4 and Swift 5

    If you just want to check the connection, and your lowest target is iOS12, then you can use NWPathMonitor

    import Network
    

    It needs a little setup with some properties.

    let internetMonitor = NWPathMonitor()
    let internetQueue = DispatchQueue(label: "InternetMonitor")
    private var hasConnectionPath = false
    

    I created a function to get it going. You can do this on view did load or anywhere else. I put a guard in so you can call it all you want to get it going.

    func startInternetTracking() {
        // only fires once
        guard internetMonitor.pathUpdateHandler == nil else {
            return
        }
        internetMonitor.pathUpdateHandler = { update in
            if update.status == .satisfied {
                print("Internet connection on.")
                self.hasConnectionPath = true
            } else {
                print("no internet connection.")
                self.hasConnectionPath = false
            }
        }
        internetMonitor.start(queue: internetQueue)
    }
    
    /// will tell you if the device has an Internet connection
    /// - Returns: true if there is some kind of connection
    func hasInternet() -> Bool {
        return hasConnectionPath
    }
    

    Now you can just call the helper function hasInternet() to see if you have one. It updates in real time. See Apple documentation for NWPathMonitor. It has lots more functionality like cancel() if you need to stop tracking the connection, type of internet you are looking for, etc. https://developer.apple.com/documentation/network/nwpathmonitor

    0 讨论(0)
  • 2020-11-22 06:09

    To solve the 4G issue mentioned in the comments I have used @AshleyMills reachability implementation as a reference and rewritten Reachability for Swift 3.1:

    updated: Xcode 10.1 • Swift 4 or later


    Reachability.swift file

    import Foundation
    import SystemConfiguration
    
    class Reachability {
        var hostname: String?
        var isRunning = false
        var isReachableOnWWAN: Bool
        var reachability: SCNetworkReachability?
        var reachabilityFlags = SCNetworkReachabilityFlags()
        let reachabilitySerialQueue = DispatchQueue(label: "ReachabilityQueue")
        init(hostname: String) throws {
            guard let reachability = SCNetworkReachabilityCreateWithName(nil, hostname) else {
                throw Network.Error.failedToCreateWith(hostname)
            }
            self.reachability = reachability
            self.hostname = hostname
            isReachableOnWWAN = true
            try start()
        }
        init() throws {
            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
            zeroAddress.sin_family = sa_family_t(AF_INET)
            guard let reachability = withUnsafePointer(to: &zeroAddress, {
                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                    SCNetworkReachabilityCreateWithAddress(nil, $0)
                }
            }) else {
                throw Network.Error.failedToInitializeWith(zeroAddress)
            }
            self.reachability = reachability
            isReachableOnWWAN = true
            try start()
        }
        var status: Network.Status {
            return  !isConnectedToNetwork ? .unreachable :
                    isReachableViaWiFi    ? .wifi :
                    isRunningOnDevice     ? .wwan : .unreachable
        }
        var isRunningOnDevice: Bool = {
            #if targetEnvironment(simulator)
                return false
            #else
                return true
            #endif
        }()
        deinit { stop() }
    }
    

    extension Reachability {
    
        func start() throws {
            guard let reachability = reachability, !isRunning else { return }
            var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
            context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
            guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
                throw Network.Error.failedToSetCallout
            }
            guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
                throw Network.Error.failedToSetDispatchQueue
            }
            reachabilitySerialQueue.async { self.flagsChanged() }
            isRunning = true
        }
    
        func stop() {
            defer { isRunning = false }
            guard let reachability = reachability else { return }
            SCNetworkReachabilitySetCallback(reachability, nil, nil)
            SCNetworkReachabilitySetDispatchQueue(reachability, nil)
            self.reachability = nil
        }
    
        var isConnectedToNetwork: Bool {
            return isReachable &&
                   !isConnectionRequiredAndTransientConnection &&
                   !(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
        }
    
        var isReachableViaWiFi: Bool {
            return isReachable && isRunningOnDevice && !isWWAN
        }
    
        /// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
        var flags: SCNetworkReachabilityFlags? {
            guard let reachability = reachability else { return nil }
            var flags = SCNetworkReachabilityFlags()
            return withUnsafeMutablePointer(to: &flags) {
                SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))
                } ? flags : nil
        }
    
        /// compares the current flags with the previous flags and if changed posts a flagsChanged notification
        func flagsChanged() {
            guard let flags = flags, flags != reachabilityFlags else { return }
            reachabilityFlags = flags
            NotificationCenter.default.post(name: .flagsChanged, object: self)
        }
    
        /// The specified node name or address can be reached via a transient connection, such as PPP.
        var transientConnection: Bool { return flags?.contains(.transientConnection) == true }
    
        /// The specified node name or address can be reached using the current network configuration.
        var isReachable: Bool { return flags?.contains(.reachable) == true }
    
        /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
        var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }
    
        /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
        var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }
    
        /// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
        var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }
    
        /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
        var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }
    
        /// The specified node name or address is one that is associated with a network interface on the current system.
        var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }
    
        /// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
        var isDirect: Bool { return flags?.contains(.isDirect) == true }
    
        /// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
        var isWWAN: Bool { return flags?.contains(.isWWAN) == true }
    
        /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
        /// The specified node name or address can be reached via a transient connection, such as PPP.
        var isConnectionRequiredAndTransientConnection: Bool {
            return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
        }
    }
    

    func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
        guard let info = info else { return }
        DispatchQueue.main.async {
            Unmanaged<Reachability>
                .fromOpaque(info)
                .takeUnretainedValue()
                .flagsChanged()
        }
    }
    

    extension Notification.Name {
        static let flagsChanged = Notification.Name("FlagsChanged")
    }
    

    struct Network {
        static var reachability: Reachability!
        enum Status: String {
            case unreachable, wifi, wwan
        }
        enum Error: Swift.Error {
            case failedToSetCallout
            case failedToSetDispatchQueue
            case failedToCreateWith(String)
            case failedToInitializeWith(sockaddr_in)
        }
    }
    

    Usage

    Initialize it in your AppDelegate.swift didFinishLaunchingWithOptions method and handle any errors that might occur:

    import UIKit
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            do {
                try Network.reachability = Reachability(hostname: "www.google.com")
            }
            catch {
                switch error as? Network.Error {
                case let .failedToCreateWith(hostname)?:
                    print("Network error:\nFailed to create reachability object With host named:", hostname)
                case let .failedToInitializeWith(address)?:
                    print("Network error:\nFailed to initialize reachability object With address:", address)
                case .failedToSetCallout?:
                    print("Network error:\nFailed to set callout")
                case .failedToSetDispatchQueue?:
                    print("Network error:\nFailed to set DispatchQueue")
                case .none:
                    print(error)
                }
            }
            return true
        }
    }
    

    And a view controller sample:

    import UIKit
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            NotificationCenter.default
                .addObserver(self,
                             selector: #selector(statusManager),
                             name: .flagsChanged,
                             object: nil)
            updateUserInterface()
        }
        func updateUserInterface() {
            switch Network.reachability.status {
            case .unreachable:
                view.backgroundColor = .red
            case .wwan:
                view.backgroundColor = .yellow
            case .wifi:
                view.backgroundColor = .green
            }
            print("Reachability Summary")
            print("Status:", Network.reachability.status)
            print("HostName:", Network.reachability.hostname ?? "nil")
            print("Reachable:", Network.reachability.isReachable)
            print("Wifi:", Network.reachability.isReachableViaWiFi)
        }
        @objc func statusManager(_ notification: Notification) {
            updateUserInterface()
        }
    }
    

    Sample Project

    0 讨论(0)
提交回复
热议问题