用Swift检查网络连接

当我试着在我的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'接受提供的参数

319271 次浏览

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

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


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

使用

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

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

样本项目 .

在你的项目中创建一个新的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() {
println("Internet connection OK")
} else {
println("Internet connection FAILED")
}

如果用户没有连接到互联网,您可能希望向他们显示一个警告对话框来通知他们。

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

解释:

我们正在制作一个可重用的公共类和方法,可以在项目的任何地方使用,以检查互联网连接。我们需要添加基础和系统配置框架。

在公共类Reachability中,方法isConnectedToNetwork() -> Bool { }将返回一个关于互联网连接的bool值。我们使用if循环对case执行所需的操作。我希望这足够了。干杯!

我使用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
}
}

我已经检查了实现阿什利米尔的可达性类没有可可荚/依赖管理器。其思想是使项目中的可达性依赖项免费。

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的父类(继承方法)。父类具有所有子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来存储常量enum值。

//  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 < / p >

如果你正在使用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
}
}

这是我自己发现的。

Xcode: 7.3.1, iOS 9.3.3

在我的项目中使用ashleymills / Reachability.swift作为reacbility .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和蜂窝网络。


添加ashleyymills的reacbility .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
}
}

对于Swift 3, Swift 4(使用蜂窝和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


}
}

用法:

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

这里是我的解决方案swift 2.3与库(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
}

在以下代码的帮助下,您可以检查蜂窝网络和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
}
}


}

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

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

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

用法:

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

虽然它没有直接回答你的问题,我想提到苹果最近有这样的谈话:

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

大约在9点55分,他谈到了做你正在问的事情:

  1. 检查连接
  2. 如果连接->做点什么
  3. 如果没有连接->执行其他操作(等待?重试?)

然而,这有一些陷阱:

  • 如果在第二步中,它说它有连接,但0.5秒后他就没有了呢?
  • 如果用户在代理的后面呢
  • 最后但并非最不重要的是,如果这里的一些答案不能确定连通性呢?(我敢肯定,如果你快速切换你的连接,去wi-fi,然后关掉它(只是让它变得复杂),它几乎永远不能正确地判断我是否获得了连接)。
  • 引用自视频:“没有办法保证未来的行动是否会成功”

以下是苹果公司的一些最佳实践:

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

这是我的版本。本质上,它没有带来任何新东西。我把它绑定到UIDevice。

import UIKit
import SystemConfiguration


extension UIDevice {


open class var isConnectedToNetwork: Bool {
get {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)


guard
let defaultRouteReachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}),
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags() as SCNetworkReachabilityFlags?,
SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
else { return false }


return flags.contains(.reachable) && !flags.contains(.connectionRequired)
}
}


}


print("Network status availability: " + ( UIDevice.isConnectedToNetwork ? "true" : "false" ))

苹果在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
}
}

虽然它可能不能直接确定手机是否连接到网络,但最简单的解决方案是“ping”谷歌或其他服务器(除非手机连接到网络,否则这是不可能的):

private var urlSession:URLSession = {
var newConfiguration:URLSessionConfiguration = .default
newConfiguration.waitsForConnectivity = false
newConfiguration.allowsCellularAccess = true
return URLSession(configuration: newConfiguration)
}()


public func canReachGoogle() -> Bool
{
let url = URL(string: "https://8.8.8.8")
let semaphore = DispatchSemaphore(value: 0)
var success = false
let task = urlSession.dataTask(with: url!)
{ data, response, error in
if error != nil
{
success = false
}
else
{
success = true
}
semaphore.signal()
}


task.resume()
semaphore.wait()


return success
}

如果您担心服务器可能宕机或阻塞您的IP,您总是可以以类似的方式ping多个服务器,并返回它们中的任何一个是否可达。或者让别人专门为这个目的设置一个专用服务器。

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

现在叫它

if Connectivity.isConnectedToInternet{
call_your_methods_here()
} else{
show_alert_for_noInternet()
}

斯威夫特5

import SystemConfiguration


protocol Utilities {}
extension NSObject: Utilities {
enum ReachabilityStatus {
case notReachable
case reachableViaWWAN
case reachableViaWiFi
}
    

var currentReachabilityStatus: ReachabilityStatus {
        

var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
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 .notReachable
}
        

var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return .notReachable
}
        

if flags.contains(.reachable) == false {
// The target host is not reachable.
return .notReachable
}
else if flags.contains(.isWWAN) == true {
// WWAN connections are OK if the calling application is using the CFNetwork APIs.
return .reachableViaWWAN
}
else if flags.contains(.connectionRequired) == false {
// If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
return .reachableViaWiFi
}
else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
// The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
return .reachableViaWiFi
}
else {
return .notReachable
}
}
}

在任何方法中使用下面的条件

if currentReachabilityStatus == .notReachable {
// Network Unavailable
} else {
// Network Available
}

将此用于Swift-5 +

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, {
            

$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                

SCNetworkReachabilityCreateWithAddress(nil, $0)
                

}
            

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

}

用法:

if InternetConnectionManager.isConnectedToNetwork(){
print("Connected")
}else{
print("Not Connected")
}

或者只是使用这个__ABC0来获取更多的Utilities: 链接

iOS12 斯威夫特4斯威夫特5

如果你只是想检查连接,而你的最低目标是iOS12,那么你可以使用NWPathMonitor

import Network

它需要一些属性的设置。

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

我创建了一个函数来启动它。你可以在viewdidload或其他地方做这个。我派了个保镖,你想怎么打就怎么打。

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
}
现在你可以调用helper函数hasInternet()来查看你是否有一个。它实时更新。有关NWPathMonitor,请参阅Apple文档。它有更多的功能,如cancel(),如果你需要停止跟踪连接,你正在寻找的互联网类型等。 https://developer.apple.com/documentation/network/nwpathmonitor < / p >

这里是接受答案的相同代码,但我发现在某些情况下使用闭包更有用

import SystemConfiguration


public class Reachability {


class func isConnectedToNetwork(isConnected : (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 {
isConnected(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)


isConnected(ret)
}
}

下面是如何使用它:

Reachability.isConnectedToNetwork { (isConnected) in
if isConnected {
//We have internet connection | get data from server
} else {
//We don't have internet connection | load from database
}
}

如果你的项目有一个高于或等于iOS 12的目标,并使用组合,你可以使用这一小段代码。

import Combine
import Network


enum NerworkType {
case wifi
case cellular
case loopBack
case wired
case other
}


protocol ReachabilityServiceContract {
var reachabilityInfos: PassthroughSubject<NWPath, Never> { get set }
var isNetworkAvailable: CurrentValueSubject<Bool, Never> { get set }
var typeOfCurrentConnection: PassthroughSubject<NerworkType, Never> { get set }
}


final class ReachabilityService: ReachabilityServiceContract {
var reachabilityInfos: PassthroughSubject<NWPath, Never> = .init()
var isNetworkAvailable: CurrentValueSubject<Bool, Never> = .init(false)
var typeOfCurrentConnection: PassthroughSubject<NerworkType, Never> = .init()


private let monitor: NWPathMonitor
private let backgroudQueue = DispatchQueue.global(qos: .background)


init() {
monitor = NWPathMonitor()
setUp()
}


init(with interFaceType: NWInterface.InterfaceType) {
monitor = NWPathMonitor(requiredInterfaceType: interFaceType)
setUp()
}


deinit {
monitor.cancel()
}
}


private extension ReachabilityService {
func setUp() {
    

monitor.pathUpdateHandler = { [weak self] path in
self?.reachabilityInfos.send(path)
switch path.status {
case .satisfied:
self?.isNetworkAvailable.send(true)
case .unsatisfied, .requiresConnection:
self?.isNetworkAvailable.send(false)
@unknown default:
self?.isNetworkAvailable.send(false)
}
if path.usesInterfaceType(.wifi) {
self?.typeOfCurrentConnection.send(.wifi)
} else if path.usesInterfaceType(.cellular) {
self?.typeOfCurrentConnection.send(.cellular)
} else if path.usesInterfaceType(.loopback) {
self?.typeOfCurrentConnection.send(.loopBack)
} else if path.usesInterfaceType(.wiredEthernet) {
self?.typeOfCurrentConnection.send(.wired)
} else if path.usesInterfaceType(.other) {
self?.typeOfCurrentConnection.send(.other)
}
}
    

monitor.start(queue: backgroudQueue)
}
}

只要订阅你想要跟踪的变量,你就会得到任何变化的更新。

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

import Foundation
import SystemConfiguration


open class Reachability {
    

class func isConnectedToNetwork() -> Bool {
        

var zeroAddress = sockaddr_in()
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()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
}

你可以在代码的任何地方调用Reachability,就像

if Reachability.isConnectedToNetwork() {
print("Network is connected")
} else {
print("Network is not connected")
}

从iOS 12开始,NWPathMonitor取代了Reachability。用这个:

import Network




struct Internet {
 

private static let monitor = NWPathMonitor()
 

static var active = false
static var expensive = false
 

/// Monitors internet connectivity changes. Updates with every change in connectivity.
/// Updates variables for availability and if it's expensive (cellular).
static func start() {
guard monitor.pathUpdateHandler == nil else { return }
  

monitor.pathUpdateHandler = { update in
Internet.active = update.status == .satisfied ? true : false
Internet.expensive = update.isExpensive ? true : false
}
  

monitor.start(queue: DispatchQueue(label: "InternetMonitor"))
}
 

}

在使用:

Internet.start()


if Internet.active {
// do something
}
  

if Internet.expensive {
// device is using Cellular data or WiFi hotspot
}

更新版本的@martin的答案Swift 5+使用组合。它还包括iOS 14的不可用原因检查。

import Combine
import Network


enum NetworkType {
case wifi
case cellular
case loopBack
case wired
case other
}


final class ReachabilityService: ObservableObject {


@Published var reachabilityInfos: NWPath?
@Published var isNetworkAvailable: Bool?
@Published var typeOfCurrentConnection: NetworkType?


private let monitor = NWPathMonitor()
private let backgroundQueue = DispatchQueue.global(qos: .background)


init() {
setUp()
}


init(with interFaceType: NWInterface.InterfaceType) {
setUp()
}


deinit {
monitor.cancel()
}
}


private extension ReachabilityService {


func setUp() {


monitor.pathUpdateHandler = { [weak self] path in
self?.reachabilityInfos = path
switch path.status {
case .satisfied:
print("ReachabilityService: satisfied")
self?.isNetworkAvailable = true
break
case .unsatisfied:
print("ReachabilityService: unsatisfied")


if #available(iOS 14.2, *) {
switch path.unsatisfiedReason {


case .notAvailable:
print("ReachabilityService: unsatisfiedReason: notAvailable")
break
case .cellularDenied:
print("ReachabilityService: unsatisfiedReason: cellularDenied")
break
case .wifiDenied:
print("ReachabilityService: unsatisfiedReason: wifiDenied")
break
case .localNetworkDenied:
print("ReachabilityService: unsatisfiedReason: localNetworkDenied")
break
@unknown default:
print("ReachabilityService: unsatisfiedReason: default")
}
} else {
// Fallback on earlier versions
}


self?.isNetworkAvailable = false
break
case .requiresConnection:
print("ReachabilityService: requiresConnection")
self?.isNetworkAvailable = false
break
@unknown default:
print("ReachabilityService: default")
self?.isNetworkAvailable = false
}
if path.usesInterfaceType(.wifi) {
self?.typeOfCurrentConnection = .wifi
} else if path.usesInterfaceType(.cellular) {
self?.typeOfCurrentConnection = .cellular
} else if path.usesInterfaceType(.loopback) {
self?.typeOfCurrentConnection = .loopBack
} else if path.usesInterfaceType(.wiredEthernet) {
self?.typeOfCurrentConnection = .wired
} else if path.usesInterfaceType(.other) {
self?.typeOfCurrentConnection = .other
}
}


monitor.start(queue: backgroundQueue)
}
}

用法:

在视图模型中:

private let reachability = ReachabilityService()


init() {
reachability.$isNetworkAvailable.sink { [weak self] isConnected in
self?.isConnected = isConnected ?? false
}.store(in: &cancelBag)
}

在你的控制器中:

viewModel.$isConnected.sink { [weak self] isConnected in
print("isConnected: \(isConnected)")
DispatchQueue.main.async {
//Update your UI in here
}
}.store(in: &bindings)

Swift 5解决方案:

    下载ashleymills的Reachability类 李https://github.com/ashleymills/Reachability.swift。< / >
  1. 将Reachability类添加到项目中。
  2. 将以下代码放入维护连接状态的类中
class ConnectionManager {


static let shared = ConnectionManager()
private init () {}


func hasConnectivity() -> Bool {
do {
let reachability: Reachability = try Reachability()
let networkStatus = reachability.connection
            

switch networkStatus {
case .unavailable:
return false
case .wifi, .cellular:
return true
}
}
catch {
return false
}
}
}
  1. 像下面这样使用它:
ConnectionManager.shared.hasConnectivity()

这些答案中有许多已经不再适用。

原因是使用vpn(因为冠状病毒,我们现在通过vpn而不是公司的wifi进行测试)

使用苹果的网络框架和基于这里找到的代码https://medium.com/@udaykiran.munaga/swift-check-for-internet-connectivity-14e355fa10c5,我能够检测到wifi和蜂窝网络各自独立。由于使用vpn,路径通常保持满意,因此isConnectedToNetwork()总是返回true。

下面的代码使用了apple Network框架,但重新编写,以便在现有代码中仍然使用Reachability.isConnectedToNetwork()。

    import Network


class Reachability {
static let shared = Reachability()


let monitorForWifi = NWPathMonitor(requiredInterfaceType: .wifi)
let monitorForCellular = NWPathMonitor(requiredInterfaceType: .cellular)
private var wifiStatus: NWPath.Status = .requiresConnection
private var cellularStatus: NWPath.Status = .requiresConnection
var isReachable: Bool { wifiStatus == .satisfied || isReachableOnCellular }
var isReachableOnCellular: Bool { cellularStatus == .satisfied }


func startMonitoring() {
monitorForWifi.pathUpdateHandler = { [weak self] path in
self?.wifiStatus = path.status


if path.status == .satisfied {
DLog.message("Wifi is connected!")
// post connected notification
} else {
DLog.message("No wifi connection.")
// post disconnected notification
}
}
monitorForCellular.pathUpdateHandler = { [weak self] path in
self?.cellularStatus = path.status


if path.status == .satisfied {
DLog.message("Cellular connection is connected!")
// post connected notification
} else {
DLog.message("No cellular connection.")
// post disconnected notification
}
}


let queue = DispatchQueue(label: "NetworkMonitor")
monitorForCellular.start(queue: queue)
monitorForWifi.start(queue: queue)
}


func stopMonitoring() {
monitorForWifi.cancel()
monitorForCellular.cancel()
}
    

class func isConnectedToNetwork() -> Bool {
return shared.isReachable
}
}

然后在你的Appdelegate中didFinishLaunchingWithOptions: start monitoring。

Reachability.shared.startMonitoring()

要在一个实例中检查互联网,可以使用Swift 5

import Foundation
import Alamofire


struct NetworkState {
var isInternetAvailable:Bool
{
return NetworkReachabilityManager()!.isReachable
}
}

并使用它:

if (NetworkState().isInternetAvailable) {
//connected to internet
}

没有真正的方法,即使api,这样做将尝试连接到一个特定的服务后,告诉你如果成功之前失败,最好的方法是尝试连接到你的服务并适当地处理错误的,如果你想要一些服务,会通知你当你成为连接,所有会发生的是,它定期调用一个固定的服务,直到得到一个响应,然后让你知道它成功,如果问题不在于互联网本身,而在于您试图连接的特定服务,该怎么办?

最好的方法是在你的连接方法中设计处理这个问题的方法,你可以在给定的时间内触发重试,这取决于你的错误,也许是失败的数量,你可以返回一个错误,你可以用它来显示一个错误消息,给用户一个重试的可能性,也许是尝试几次,然后返回和错误的组合。

另一个类似的问题是发送你已经发送但还没有得到响应的消息,最好还是写你的应用程序来处理这个,忽略请求,直到它等待的请求返回,如果请求不同,取消等待请求,等等

这些东西可以以非常通用的方式编写,所以它们可以用于应用程序的许多不同方面,甚至不同的项目。

斯威夫特5.5iOS 12 +,没有更多的第三方库。

请核对一下要点 https://gist.github.com/dimohamdy/5166ba6c88f6954fa6b23bc9f28cbe12

使用

 startNetworkReachabilityObserver()
 

if Reachability.shared.isConnected {
print("no internet connection")
}

代码

import Network
import Foundation


class Reachability {


static var shared = Reachability()
lazy private var monitor = NWPathMonitor()


var isConnected: Bool {
return monitor.currentPath.status == .satisfied
}


func startNetworkReachabilityObserver() {
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
NotificationCenter.default.post(name: Notifications.Reachability.connected.name, object: nil)
} else if path.status == .unsatisfied {
NotificationCenter.default.post(name: Notifications.Reachability.notConnected.name, object: nil)
}
}
let queue = DispatchQueue.global(qos: .background)
monitor.start(queue: queue)
}
}

Xcode 14.0, Swift 5.7

要检查互联网连接,使用苹果的原生Network框架。它有NWPathMonitor类观察者,你可以实现它来监视和响应网络变化。

import Network


class ViewController: UIViewController {
@IBOutlet var label: UILabel!
    

override func viewDidLoad() {
super.viewDidLoad()
self.networkMonitoring()
}
    

fileprivate func networkMonitoring() {
let monitor = NWPathMonitor()
let queue = DispatchQueue(label: "monitoring")
monitor.start(queue: queue)
        

monitor.pathUpdateHandler = { path in
DispatchQueue.main.async {
switch path.status {
case .satisfied:
self.label.text = "Intenet connected"
self.view.backgroundColor = .systemGreen
case .unsatisfied:
self.label.text = "No Intenet"
self.view.backgroundColor = .systemRed
case .requiresConnection:
self.label.text = "May be activated"
self.view.backgroundColor = .systemBlue
@unknown default:  fatalError()
}
}
}
}
}

我对Lex的例子做了一些改进。我添加了一些额外的控件来解决双重触发问题,还添加了通知支持来侦听状态更改。

我为防止双重触发问题而添加的控件还显示了设备主要使用哪个连接源来访问互联网。

例如,即使设备同时连接蜂窝网络和Wi-Fi,“状态”;返回为“connectedViaWiFi"到表示当前的互联网接入是Wi-Fi。

import Foundation
import Network


class Reachability {


enum StatusFlag {
case unknow
case noConnection
case connectedViaWiFi
case connectedViaCellular
}


static let connectionStatusHasChangedNotification = NSNotification.Name("Reachability.connectionStatusHasChangedNotification")
static let shared = Reachability()


private var monitorForWifi: NWPathMonitor?
private var monitorForCellular: NWPathMonitor?
private var wifiStatus: NWPath.Status = .requiresConnection
private var cellularStatus: NWPath.Status = .requiresConnection
private var ignoreInitialWiFiStatusUpdate: Bool = true
private var ignoreInitialCelluluarStatusUpdate: Bool = true
private var isReachableOnCellular: Bool { cellularStatus == .satisfied }
private var isReachableOnWiFi: Bool { wifiStatus == .satisfied }
var status: StatusFlag = .unknow {
didSet {
guard status != oldValue else { return }
DispatchQueue.main.async { [weak self] in
NotificationCenter.default.post(name: Self.connectionStatusHasChangedNotification,
object: self?.status)
}
}
}


func startMonitoring() {
monitorForWifi = NWPathMonitor(requiredInterfaceType: .wifi)
monitorForWifi?.pathUpdateHandler = { [weak self] path in
self?.wifiStatus = path.status
self?.ignoreInitialWiFiStatusUpdate = false
self?.updateStatus()
}
monitorForCellular = NWPathMonitor(requiredInterfaceType: .cellular)
monitorForCellular?.pathUpdateHandler = { [weak self] path in
self?.cellularStatus = path.status
self?.ignoreInitialCelluluarStatusUpdate = false
self?.updateStatus()
}
let queue = DispatchQueue.global(qos: .background)
monitorForCellular?.start(queue: queue)
monitorForWifi?.start(queue: queue)
}


func stopMonitoring() {
monitorForWifi?.cancel()
monitorForWifi = nil
monitorForCellular?.cancel()
monitorForCellular = nil
wifiStatus = .requiresConnection
cellularStatus = .requiresConnection
status = .unknow
ignoreInitialWiFiStatusUpdate = true
ignoreInitialCelluluarStatusUpdate = true
}


private func updateStatus() {
if ignoreInitialWiFiStatusUpdate || ignoreInitialCelluluarStatusUpdate {
return
}
if !(isReachableOnCellular && isReachableOnWiFi) {
if isReachableOnCellular && !isReachableOnWiFi {
status = .connectedViaCellular
} else if isReachableOnWiFi && !isReachableOnCellular {
status = .connectedViaWiFi
} else {
status = .noConnection
}
} else {
status = .connectedViaWiFi
}
}


static func isConnectedToNetwork() -> Bool {
return shared.isReachableOnCellular || shared.isReachableOnWiFi
}
}

示例使用

    override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(_:)), name: Reachability.connectionStatusHasChangedNotification, object: nil)
Reachability.shared.startMonitoring()
}


@objc func reachabilityChanged(_ sender: Notification) {
guard let statusFlag = sender.object as? Reachability.StatusFlag else { return }
print("TEST -> statusFlag: \(statusFlag)")
}