ios 使用 Swift 检查互联网连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30743408/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:18:59  来源:igfitidea点击:

Check for internet connection with Swift

iosswiftxcodereachability

提问by b3rge

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?

当我尝试在我的 iPhone 上检查互联网连接时,我收到了一堆错误。谁能帮我解决这个问题?

The code:

编码:

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(
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, {
            
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(
func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    guard let info = info else { return }
    DispatchQueue.main.async {
        Unmanaged<Reachability>
            .fromOpaque(info)
            .takeUnretainedValue()
            .flagsChanged()
    }
}
)) } ? 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 } }
.withMemoryRebound(to: sockaddr.self, capacity: 1) { SCNetworkReachabilityCreateWithAddress(nil,
extension Notification.Name {
    static let flagsChanged = Notification.Name("FlagsChanged")
}
) } }) 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() } }
)) } 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 } }

The errors with the code:

代码错误:

Errors

错误

If it is unreadable, error 1 says:

如果不可读,错误 1 ​​表示:

'Int' is not convertible to 'SCNetworkReachabilityFlags'

“Int”不可转换为“SCNetworkReachabilityFlags”

Error 2 & 3:

错误 2 和 3:

Could not find an overload for 'init' that accepts the supplied arguments

找不到接受提供的参数的“init”的重载

回答by Leo Dabus

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:

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

updated: Xcode 10.1 ? Swift 4 or later

更新:Xcode 10.1?Swift 4 或更高版本



Reachability.swift file

Reachability.swift 文件

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


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


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


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) {
            
if Reachability.isConnectedToNetwork(){
    print("Internet Connection Available!")
}else{
    print("Internet Connection not Available!")
}
.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 } }


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(
if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
}
)) } var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0) if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false { return false } let isReachable = flags == .Reachable let needsConnection = flags == .ConnectionRequired return isReachable && !needsConnection } }


Usage

用法

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

在你的 AppDelegate.swift didFinishLaunchingWithOptions 方法中初始化它并处理可能发生的任何错误:

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


And a view controller sample:

和一个视图控制器示例:

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

Sample Project

示例项目

回答by Rajamohan S

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

对于 Swift 3、Swift 4(使用蜂窝网络和 Wi-Fi):

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

Usage:

用法:

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

回答by A.G

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

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

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

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

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

//  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")
            }
        }
    }

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

如果用户未连接到 Internet,您可能希望向他们显示警报对话框以通知他们。

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

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!

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

回答by Hyman

If someone is already using Alamofirethen -

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

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

  case WIFI_NETWORK = "Wifi"
  case WWAN_NETWORK = "Cellular"
  case OTHER = "Other"

}

Usage:

用法:

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

回答by A.G

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.

我已经检查了在没有 Cocoa Pods/Dependancy Manager 的情况下实现 Ashley Mill 的 Reachability 类。这个想法是使项目中的 Reachability 依赖项免费。

Xcode 7.2 - Swift 2.1

Xcode 7.2 - 斯威夫特 2.1

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

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

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.

2) 创建一个 AppManager.swift 类。此类将作为公共模型类提供服务,其中将添加公共方法和数据,并可在任何 VC 中使用。

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

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

3) 做一个委托类。我使用委托方法来通知连接状态。

import Foundation
import UIKit
import SystemConfiguration

public class InternetConnectionManager {


    private init() {

    }

    public static func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {

            
InternetConnectionManager.isConnectedToNetwork{
    print("Connected")
}else{
    print("Not Connected")
}
.withMemoryRebound(to: sockaddr.self, capacity: 1) { SCNetworkReachabilityCreateWithAddress(nil,
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
    }
}
) } }) else { return false } var flags = SCNetworkReachabilityFlags() if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { return false } let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0 let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0 return (isReachable && !needsConnection) } }

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

4) 创建 UIViewController 的父类(继承方法)。父类具有所有子 VC 都可以访问的方法。

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(
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
                                    }
                                }
)) }) 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(##代码##)) }) 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(##代码##)) } 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 } }

5) Start Real time Internet Connectivity Monitoring in AppDelegate.

5) 在 AppDelegate 中启动实时 Internet 连接监控。

##代码##

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

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

##代码##

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

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

##代码##

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

示例可以在@ https://github.com/alvinreuben/Reachability-Sample下载

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

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

回答by Yogendra Singh

Apple has introduced Network Framework in iOS12.

苹果在 iOS12 中引入了网络框架。

##代码##

回答by Jamil Hasnine Tamim

Use this for Swift-5+

将此用于Swift-5+

##代码##

Usage:

用法:

##代码##

Or Just use this frameworkfor more Utilities: Link

或者只是使用它framework来获取更多信息Utilities链接

回答by J. Doe

Although it does not directlyanswers your question, I would like to mention Apple recentely had this talk:

虽然它没有直接回答你的问题,但我想提一下苹果最近有这样一个演讲:

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

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

At around 09:55 he talks about doing this stuff you are asking about:

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

  1. Check connection
  2. If connection -> Do something
  3. If no connection -> Do something else (wait? retry?)
  1. 检查连接
  2. 如果连接 -> 做某事
  3. 如果没有连接 -> 做其他事情(等待?重试?)

However, this has a few pitfalls:

但是,这有一些陷阱:

  • What if in step 2 it says it has a connection, but 0.5 seconds later he hasn't?
  • What if the user is behind a proxy
  • Last but not least, what if some answers here can not determine the connectivity right? (I am sure that if you rapidly switch your connection, go to wi-fi and turn it off (just make it complicated), it almost never can correctly determine whetever I got a connection or not).
  • Quote from the video: "There is no way to guarentee whether a future operation will succeed or not"
  • 如果在第 2 步中它说它有连接,但 0.5 秒后他没有连接怎么办?
  • 如果用户在代理后面怎么办
  • 最后但并非最不重要的一点是,如果这里的某些答案无法确定连接是否正确怎么办?(我敢肯定,如果您快速切换连接,转到 wi-fi 并将其关闭(只是让它变得复杂),它几乎永远无法正确确定我是否有连接)。
  • 引自视频:“没有办法保证未来的手术是否会成功”

The following points are some best practices according to Apple:

以下几点是 Apple 的一些最佳实践:

According to the talk, 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.

根据谈话,无论您是否有互联网连接,都不应该有任何理由预先检查,因为在您将请求发送到服务器时它可能不准确

回答by cmeadows

Just figured this out for myself.

只是为自己想通了这一点。

Xcode: 7.3.1, iOS 9.3.3

Xcode:7.3.1,iOS 9.3.3

Using ashleymills/Reachability.swiftas Reachability.swift in my project, I created the following function:

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

##代码##

Simply call hasConnectivity()where ever you need to check for a connection. This works for Wifi as well as Cellular.

只需hasConnectivity()在需要检查连接的地方拨打电话即可。这适用于 Wifi 和蜂窝网络。



Adding ashleymills's Reachability.swift so people dont have to move between sites:

添加 ashleymills 的 Reachability.swift 以便人们不必在站点之间移动:

##代码##

回答by Illya Krit

If you are using Alamofire, you can do something like this:

如果您使用的是 Alamofire,您可以执行以下操作:

##代码##