首页 文章

检查与Swift的互联网连接

提问于
浏览
200

当我尝试在我的iPhone上检查互联网连接时,我收到了一堆错误 . 任何人都可以帮我解决这个问题吗?

代码:

import Foundation
import SystemConfiguration

public class Reachability {

class func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    }

    var flags: SCNetworkReachabilityFlags = 0

    if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
        return false
    }

    let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0

    return (isReachable && !needsConnection) ? true : false
}

}

代码中的错误:

Errors

如果不可读,错误1说:

'Int'不能转换为'SCNetworkReachabilityFlags'

错误2和3:

找不到接受所提供参数的'init'的重载

12 回答

  • 2

    Xcode 8.3 • Swift 3.1

    为了解决评论中提到的4G问题,我使用了@AshleyMills可达性实现作为参考并重写了Swift 3.1的Reachability:


    Reachability.swift文件

    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
        }
        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
        }
        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, CustomStringConvertible {
            case unreachable, wifi, wwan
            var description: String { return rawValue }
        }
        enum Error: Swift.Error {
            case failedToSetCallout
            case failedToSetDispatchQueue
            case failedToCreateWith(String)
            case failedToInitializeWith(sockaddr_in)
        }
    }
    

    将此添加到您的AppDelegate didFinishLaunchingWithOptions方法

    do {
        Network.reachability = try Reachability(hostname: "www.google.com")
        do {
            try Network.reachability?.start()
        } catch let error as Network.Error {
            print(error)
        } catch {
            print(error)
        }
    } catch {
        print(error)
    }
    

    和视图控制器示例:

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

    Sample Project

  • 55

    For Swift 3, Swift 4 (working with cellular and Wi-Fi):

    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(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
            }
    
            /* Only Working for WIFI
            let isReachable = flags == .reachable
            let needsConnection = flags == .connectionRequired
    
            return isReachable && !needsConnection
            */
    
            // Working for Cellular and WIFI
            let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
            let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
            let ret = (isReachable && !needsConnection)
    
            return ret
    
        }
    }
    

    Usage:

    if Reachability.isConnectedToNetwork(){
        print("Internet Connection Available!")
    }else{
        print("Internet Connection not Available!")
    }
    
  • 154

    在项目中创建一个新的Swift文件,将其命名为 Reachability.swift . 将以下代码剪切并粘贴到其中以创建您的类 .

    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
    
        }
    }
    

    您可以使用以下代码检查项目中任何位置的互联网连接:

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

    如果用户未连接到Internet,您可能需要向他们显示警告对话框以通知他们 .

    if Reachability.isConnectedToNetwork() == true {
        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:

    我们正在制作一个可重复使用的公共类和一种方法,可以在项目的任何地方使用它来检查互联网连接 . 我们需要添加Foundation和System Configuration框架 .

    在公共类Reachability中,方法 isConnectedToNetwork() -> Bool { } 将返回有关Internet连接的bool值 . 我们使用if循环对case进行必要的操作 . 我希望这已经足够了 . 干杯!

  • 2

    如果有人已经在使用Alamofire那么 -

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

    Usage:

    if Connectivity.isConnectedToInternet {
         print("Connected")
     } else {
         print("No Internet")
    }
    
  • 1

    我已经检查过没有Cocoa Pods / Dependancy Manager的实施Ashley Mill的Reachability类 . 我们的想法是在项目中使Reachability依赖免费 .

    Xcode 7.2 - Swift 2.1

    1)https://github.com/ashleymills/Reachability.swift . 下载将Reachability类添加到项目中 .

    注意:添加时,请确保勾选“复制项目(如果需要)” .

    2)创建一个AppManager.swift类 . 此类将作为公共模型类来提供,其中将添加公共方法和数据,并且可以在任何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)组建代表班 . 我使用委托方法来通知连接状态 .

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

    4)制作UIViewController的Parent类(继承方法) . 父类具有可访问所有子VC的方法 .

    //  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)在AppDelegate中启动实时Internet连接监控 .

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

    6)我添加了一个Swift文件名AppReference来存储常量枚举值 .

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

    7)在ViewController上(例如,只有在网络可用时才想调用API)

    //  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() {
      }
    }
    

    样本可以下载@ https://github.com/alvinreuben/Reachability-Sample

    升级到Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3

  • 14

    刚刚为自己想出了这个 .

    Xcode:7.3.1,iOS 9.3.3

    在我的项目中使用ashleymills/Reachability.swift作为Reachability.swift,我创建了以下函数:

    func hasConnectivity() -> Bool {
        do {
            let reachability: Reachability = try Reachability.reachabilityForInternetConnection()
            let networkStatus: Int = reachability.currentReachabilityStatus.hashValue
    
            return (networkStatus != 0)
        }
        catch {
            // Handle error however you please
            return false
        }
    }
    

    只需调用 hasConnectivity() ,您需要检查连接 . 这适用于Wifi和Cellular .


    添加ashleymills的Reachability.swift,这样人们就不必在站点之间移动:

    Copyright (c) 2014, Ashley Mills
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    
    1. Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
    
    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
    */
    
    // Reachability.swift version 2.2beta2
    
    import SystemConfiguration
    import Foundation
    
    public enum ReachabilityError: ErrorType {
        case FailedToCreateWithAddress(sockaddr_in)
        case FailedToCreateWithHostname(String)
        case UnableToSetCallback
        case UnableToSetDispatchQueue
    }
    
    public let ReachabilityChangedNotification = "ReachabilityChangedNotification"
    
    func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
        let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
    
        dispatch_async(dispatch_get_main_queue()) {
            reachability.reachabilityChanged(flags)
        }
    }
    
    
    public class Reachability: NSObject {
    
        public typealias NetworkReachable = (Reachability) -> ()
        public typealias NetworkUnreachable = (Reachability) -> ()
    
        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"
                }
            }
        }
    
        // MARK: - *** Public properties ***
        public var whenReachable: NetworkReachable?
        public var whenUnreachable: NetworkUnreachable?
        public var reachableOnWWAN: Bool
        public var notificationCenter = NSNotificationCenter.defaultCenter()
    
        public var currentReachabilityStatus: NetworkStatus {
            if isReachable() {
                if isReachableViaWiFi() {
                    return .ReachableViaWiFi
                }
                if isRunningOnDevice {
                    return .ReachableViaWWAN
                }
            }
            return .NotReachable
        }
    
        public var currentReachabilityString: String {
            return "\(currentReachabilityStatus)"
        }
    
        private var previousFlags: SCNetworkReachabilityFlags?
    
        // MARK: - *** Initialisation methods ***
    
        required public init(reachabilityRef: SCNetworkReachability) {
            reachableOnWWAN = true
            self.reachabilityRef = reachabilityRef
        }
    
        public convenience init(hostname: String) throws {
    
            let nodename = (hostname as NSString).UTF8String
            guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }
    
            self.init(reachabilityRef: ref)
        }
    
        public class func reachabilityForInternetConnection() throws -> Reachability {
    
            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)
    
            guard let ref = withUnsafePointer(&zeroAddress, {
                SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
            }) else { throw ReachabilityError.FailedToCreateWithAddress(zeroAddress) }
    
            return Reachability(reachabilityRef: ref)
        }
    
        public class func reachabilityForLocalWiFi() throws -> Reachability {
    
            var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
            localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
            localWifiAddress.sin_family = sa_family_t(AF_INET)
    
            // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
            let address: UInt32 = 0xA9FE0000
            localWifiAddress.sin_addr.s_addr = in_addr_t(address.bigEndian)
    
            guard let ref = withUnsafePointer(&localWifiAddress, {
                SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
            }) else { throw ReachabilityError.FailedToCreateWithAddress(localWifiAddress) }
    
            return Reachability(reachabilityRef: ref)
        }
    
        // MARK: - *** Notifier methods ***
        public func startNotifier() throws {
    
            guard !notifierRunning else { return }
    
            var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
            context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())
    
            if !SCNetworkReachabilitySetCallback(reachabilityRef!, callback, &context) {
                stopNotifier()
                throw ReachabilityError.UnableToSetCallback
            }
    
            if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef!, reachabilitySerialQueue) {
                stopNotifier()
                throw ReachabilityError.UnableToSetDispatchQueue
            }
    
            // Perform an intial check
            dispatch_async(reachabilitySerialQueue) { () -> Void in
                let flags = self.reachabilityFlags
                self.reachabilityChanged(flags)
            }
    
            notifierRunning = true
        }
    
        public func stopNotifier() {
            defer { notifierRunning = false }
            guard let reachabilityRef = reachabilityRef else { return }
    
            SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
            SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
        }
    
        // MARK: - *** Connection test methods ***
        public func isReachable() -> Bool {
            let flags = reachabilityFlags
            return isReachableWithFlags(flags)
        }
    
        public func isReachableViaWWAN() -> Bool {
    
            let flags = reachabilityFlags
    
            // Check we're not on the simulator, we're REACHABLE and check we're on WWAN
            return isRunningOnDevice && isReachable(flags) && isOnWWAN(flags)
        }
    
        public func isReachableViaWiFi() -> Bool {
    
            let flags = reachabilityFlags
    
            // Check we're reachable
            if !isReachable(flags) {
                return false
            }
    
            // Must be on WiFi if reachable but not on an iOS device (i.e. simulator)
            if !isRunningOnDevice {
                return true
            }
    
            // Check we're NOT on WWAN
            return !isOnWWAN(flags)
        }
    
        // MARK: - *** Private methods ***
        private var isRunningOnDevice: Bool = {
            #if (arch(i386) || arch(x86_64)) && os(iOS)
                return false
            #else
                return true
            #endif
        }()
    
        private var notifierRunning = false
        private var reachabilityRef: SCNetworkReachability?
        private let reachabilitySerialQueue = dispatch_queue_create("uk.co.ashleymills.reachability", DISPATCH_QUEUE_SERIAL)
    
        private func reachabilityChanged(flags: SCNetworkReachabilityFlags) {
    
            guard previousFlags != flags else { return }
    
            if isReachableWithFlags(flags) {
                if let block = whenReachable {
                    block(self)
                }
            } else {
                if let block = whenUnreachable {
                    block(self)
                }
            }
    
            notificationCenter.postNotificationName(ReachabilityChangedNotification, object:self)
    
            previousFlags = flags
        }
    
        private func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {
    
            if !isReachable(flags) {
                return false
            }
    
            if isConnectionRequiredOrTransient(flags) {
                return false
            }
    
            if isRunningOnDevice {
                if isOnWWAN(flags) && !reachableOnWWAN {
                    // We don't want to connect when on 3G.
                    return false
                }
            }
    
            return true
        }
    
        // WWAN may be available, but not active until a connection has been established.
        // WiFi may require a connection for VPN on Demand.
        private func isConnectionRequired() -> Bool {
            return connectionRequired()
        }
    
        private func connectionRequired() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags)
        }
    
        // Dynamic, on demand connection?
        private func isConnectionOnDemand() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags) && isConnectionOnTrafficOrDemand(flags)
        }
    
        // Is user intervention required?
        private func isInterventionRequired() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags) && isInterventionRequired(flags)
        }
    
        private func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
            #if os(iOS)
                return flags.contains(.IsWWAN)
            #else
                return false
            #endif
        }
        private func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.Reachable)
        }
        private func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionRequired)
        }
        private func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.InterventionRequired)
        }
        private func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionOnTraffic)
        }
        private func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionOnDemand)
        }
        func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
            return !flags.intersect([.ConnectionOnTraffic, .ConnectionOnDemand]).isEmpty
        }
        private func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.TransientConnection)
        }
        private func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.IsLocalAddress)
        }
        private func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.IsDirect)
        }
        private func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
            let testcase:SCNetworkReachabilityFlags = [.ConnectionRequired, .TransientConnection]
            return flags.intersect(testcase) == testcase
        }
    
        private var reachabilityFlags: SCNetworkReachabilityFlags {
    
            guard let reachabilityRef = reachabilityRef else { return SCNetworkReachabilityFlags() }
    
            var flags = SCNetworkReachabilityFlags()
            let gotFlags = withUnsafeMutablePointer(&flags) {
                SCNetworkReachabilityGetFlags(reachabilityRef, UnsafeMutablePointer($0))
            }
    
            if gotFlags {
                return flags
            } else {
                return SCNetworkReachabilityFlags()
            }
        }
    
        override public var description: String {
    
            var W: String
            if isRunningOnDevice {
                W = isOnWWAN(reachabilityFlags) ? "W" : "-"
            } else {
                W = "X"
            }
            let R = isReachable(reachabilityFlags) ? "R" : "-"
            let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
            let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
            let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
            let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
            let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
            let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
            let d = isDirect(reachabilityFlags) ? "d" : "-"
    
            return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
        }
    
        deinit {
            stopNotifier()
    
            reachabilityRef = nil
            whenReachable = nil
            whenUnreachable = nil
        }
    }
    
  • 0

    我使用NSTimer和Alamofire制作了自己的解决方案:

    import Alamofire
    
    public class ConnectionHelper: NSObject {
        var request: Alamofire.Request?
    
        func isInternetConnected(completionHandler: Bool -> Void) {
            NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "requestTimeout", userInfo: nil, repeats: false)
    
            request = Alamofire
                .request(
                    Method.HEAD,
                    "http://www.testurl.com"
                )
                .response { response in
                    if response.3?.code == -999 {
                        completionHandler(
                            false
                        )
                    } else {
                        completionHandler(
                            true
                        )
                    }
            }
        }
    
        func requestTimeout() {
            request!.cancel()
        }
    }
    

    NSTimer用作超时,并且由于使用Alamofire超时的结果不可靠而被使用 . 请求应该是您信任的可靠URL,例如您自己的服务器或托管您所依赖的服务的服务器 .

    当计时器到期时,取消请求并使用完成处理程序返回结果 .

    用法:

    ConnectionHelper().isInternetConnected() { internetConnected in
        if internetConnected {
            // Connected
        } else {
            // Not connected
        }
    }
    
  • 8

    如果您使用的是Alamofire,您可以这样做:

    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    configuration.timeoutIntervalForRequest = 15 //Set timeouts in sec
    configuration.timeoutIntervalForResource = 15
    
    let alamoFireManager = Alamofire.Manager(configuration:configuration)
    alamoFireManager?.request(.GET, "https://yourURL.com", parameters: headers, encoding: .URL)
                         .validate()
                                  .responseJSON { response in
    
                                    if let error = response.result.error {
                                       switch error.code{
                                        case -1001:
                                            print("Slow connection")
                                            return
                                        case -1009:
                                            print("No Connection!")
                                            return
                                        default: break
                                        }
                                    }
    
  • 328

    这里我的解决方案为swift 2.3与lib(Reachability.swift

    进入你的 Podfile 并添加:

    pod 'ReachabilitySwift', '~> 2.4' // swift 2.3
    

    然后进入你的 terminal

    pod install
    

    然后创建一个新文件 ReachabilityManager 并在下面添加代码:

    import Foundation
    import ReachabilitySwift
    
    enum ReachabilityManagerType {
        case Wifi
        case Cellular
        case None
    }
    
    class ReachabilityManager {
        static let sharedInstance = ReachabilityManager()
    
        private var reachability: Reachability!
        private var reachabilityManagerType: ReachabilityManagerType = .None
    
    
        private init() {
            do {
                self.reachability = try Reachability.reachabilityForInternetConnection()
            } catch {
                print("Unable to create Reachability")
                return
            }
    
            NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ReachabilityManager.reachabilityChanged(_:)),name: ReachabilityChangedNotification,object: self.reachability)
            do{
                try self.reachability.startNotifier()
            }catch{
                print("could not start reachability notifier")
            }
        }
    
        @objc private func reachabilityChanged(note: NSNotification) {
    
            let reachability = note.object as! Reachability
    
            if reachability.isReachable() {
                if reachability.isReachableViaWiFi() {
                    self.reachabilityManagerType = .Wifi
                } else {
                    self.reachabilityManagerType = .Cellular
                }
            } else {
                self.reachabilityManagerType = .None
            }
        }
    }
    
    extension ReachabilityManager {
    
        func isConnectedToNetwork() -> Bool {
            return reachabilityManagerType != .None
        }
    
    }
    

    怎么用呢:

    进入 AppDelegate.swift 并添加以下代码:

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

    然后,当您要检查设备是否已连接到互联网时:

    if ReachabilityManager.sharedInstance.isConnectedToNetwork() {
       // Connected
    } else {
      // Not connected
    }
    
  • 0

    虽然它没有直接回答你的问题,但我想提一下Apple对这个话题的接受:

    https://developer.apple.com/videos/play/wwdc2018/714/

    在09:55左右,他谈到做你要问的这些事情:

    • 检查连接

    • 如果连接 - >做某事

    • 如果没有连接 - >做其他事情(等等?重试?)

    但是,这有一些陷阱:

    • 如果在步骤2中它表示有连接,但0.5秒后他没有连接怎么办?

    • 如果用户在代理后面怎么办?

    • 最后但并非最不重要的,如果此处的某些答案无法确定连接性,该怎么办? (我相信如果你快速切换你的连接,去wi-fi并关闭它(只是让它变得复杂),它几乎永远不能正确地确定我有没有连接) .

    • 来自视频的引用:"There is no way to guarentee whether a future operation will succeed or not"

    为了更好地联网,请执行以下操作:

    根据谈话, there shouldn't be any reason to pre-check whetever you got internet connection or not, since it may not be accurate at the time you send your request to the server .

  • 27

    在下面的代码的帮助下,您可以检查蜂窝网络和WiFi的互联网连接 . 语言 - Swift 3.0

    import UIKit
    import Foundation
    import SystemConfiguration
    
    class NetworkConnection: UIViewController {
    
      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 checkConnection(sender:UIViewController){
        if NetworkConnection.isConnectedToNetwork() == true {
          print("Connected to the internet")
          //  Do something
        } else {
          print("No internet connection")
          let alertController = UIAlertController(title: "No Internet Available", message: "", preferredStyle: UIAlertControllerStyle.alert)
          let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){(result:UIAlertAction) -> Void in
            return
          }
          alertController.addAction(okAction)
          sender.present(alertController, animated: true, completion: nil)
          //  Do something
        }
      }
    
    }
    
  • 1

    对于swift 3,我无法使用RAJAMOHAN-S解决方案中的可达性,因为如果有WiFi但没有互联网,它会返回“true” . 因此,我通过URLSession类和完成处理程序实现了第二次验证 .

    这是全班 .

    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(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
    }
    
    // Working for Cellular and WIFI
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    let ret = (isReachable && !needsConnection)
    
    return ret
    }
    
    
    
    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
    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()
    }
    }
    

    你这样称呼它,例如:

    Reachability.isInternetAvailable(webSiteToPing: nil) { (isInternetAvailable) in
      guard isInternetAvailable else {
        // Inform user for example
        return
      }
    
      // Do some action if there is Internet
    }
    

相关问题