使用 Swift 检查互联网连接
Check for internet connection with 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([=11=]))
}
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
}
}
代码错误:
如果不可读,错误 1 表示:
'Int' is not convertible to 'SCNetworkReachabilityFlags'
错误 2 和 3:
Could not find an overload for 'init' that accepts the supplied arguments
为了解决评论中提到的 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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([=11=]))
} ? 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
。将以下代码剪切并粘贴到其中以创建您的 class.
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer([=10=]))
}
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")
}
如果用户未连接到 Internet,您可能希望向他们显示一个警告对话框以通知他们。
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()
}
解释:
我们正在制作一个可重复使用的 public class 和一个可以在项目中的任何地方使用的方法来检查互联网连接。我们需要添加基础和系统配置框架。
在 public class 可达性中,方法 isConnectedToNetwork() -> Bool { }
将 return 一个关于互联网连接的布尔值。我们使用 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
}
}
我已经检查了在没有 Cocoa Pods/Dependancy 管理器的情况下实施 Ashley Mill 的可达性 class。这个想法是使项目中的可达性依赖自由。
Xcode 7.2 - Swift 2.1
1) https://github.com/ashleymills/Reachability.swift。下载将 Reachability class 添加到项目中。
注意:添加时,请确保勾选'copy items if needed'。
2) 制作一个 AppManager.swift class 。此 class 将迎合 Public 模型 class,其中 public 方法和数据将被添加并可用于任何 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) 创建委托 Class。我使用委托方法来通知连接状态。
// Protocols.swift
import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {
func reachabilityStatusChangeHandler(reachability:Reachability)
}
4) 使 UIViewController 的父级 class(继承方法)。父 class 具有所有子 VC 都可以访问的方法。
// UIappViewController.swift
import UIKit
class UIappViewController: UIViewController,AppManagerDelegate {
var manager:AppManager = AppManager.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func reachabilityStatusChangeHandler(reachability: Reachability) {
if reachability.isReachable() {
print("isReachable")
} else {
print("notReachable")
}
}
}
5) 在 AppDelegate 中启动实时 Internet 连接监控。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
AppManager.sharedInstance.initRechabilityMonitor()
return true
}
6) 我添加了一个 Swift 文件名 AppReference 来存储常量枚举值。
// AppReference.swift
import Foundation
enum CONNECTION_NETWORK_TYPE : String {
case WIFI_NETWORK = "Wifi"
case WWAN_NETWORK = "Cellular"
case OTHER = "Other"
}
7) 在 ViewController 上(例如,您只想在网络可用时调用 API)
// ViewController.swift
import UIKit
class ViewController: UIappViewController {
var reachability:Reachability?
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
if(AppManager.sharedInstance.isReachability)
{
print("net available")
//call API from here.
} else {
dispatch_async(dispatch_get_main_queue()) {
print("net not available")
//Show Alert
}
}
//Determine Network Type
if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
{
print(".Wifi")
}
else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
{
print(".Cellular")
}
else {
dispatch_async(dispatch_get_main_queue()) {
print("Network not reachable")
}
}
}
override func viewWillAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
}
}
样本可以下载@https://github.com/alvinreuben/Reachability-Sample
升级到 Swift 3.1-
https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3
如果你使用的是 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 作为 Reachability.swift,我创建了以下函数:
func hasConnectivity() -> Bool {
do {
let reachability: Reachability = try Reachability.reachabilityForInternetConnection()
let networkStatus: Int = reachability.currentReachabilityStatus.hashValue
return (networkStatus != 0)
}
catch {
// Handle error however you please
return false
}
}
只需在需要检查连接的地方调用 hasConnectivity()
。这适用于 Wifi 和蜂窝网络。
添加 ashleymills 的 Reachability.swift 这样人们就不必在站点之间移动:
Copyright (c) 2014, Ashley Mills
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Reachability.swift version 2.2beta2
import SystemConfiguration
import Foundation
public enum ReachabilityError: ErrorType {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
public let ReachabilityChangedNotification = "ReachabilityChangedNotification"
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
dispatch_async(dispatch_get_main_queue()) {
reachability.reachabilityChanged(flags)
}
}
public class Reachability: NSObject {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
public enum NetworkStatus: CustomStringConvertible {
case NotReachable, ReachableViaWiFi, ReachableViaWWAN
public var description: String {
switch self {
case .ReachableViaWWAN:
return "Cellular"
case .ReachableViaWiFi:
return "WiFi"
case .NotReachable:
return "No Connection"
}
}
}
// MARK: - *** Public properties ***
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
public var reachableOnWWAN: Bool
public var notificationCenter = NSNotificationCenter.defaultCenter()
public var currentReachabilityStatus: NetworkStatus {
if isReachable() {
if isReachableViaWiFi() {
return .ReachableViaWiFi
}
if isRunningOnDevice {
return .ReachableViaWWAN
}
}
return .NotReachable
}
public var currentReachabilityString: String {
return "\(currentReachabilityStatus)"
}
private var previousFlags: SCNetworkReachabilityFlags?
// MARK: - *** Initialisation methods ***
required public init(reachabilityRef: SCNetworkReachability) {
reachableOnWWAN = true
self.reachabilityRef = reachabilityRef
}
public convenience init(hostname: String) throws {
let nodename = (hostname as NSString).UTF8String
guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }
self.init(reachabilityRef: ref)
}
public class func reachabilityForInternetConnection() throws -> Reachability {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let ref = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer([=11=]))
}) 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([=11=]))
}) 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([=11=]))
}
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) {
[=10=].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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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 解决方案的可达性,因为它 returns "true" 如果有 WiFi 但没有互联网。因此,我通过 URLSession class 和完成处理程序实现了第二次验证。
这里是全文class。
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
[=10=].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")
}
虽然它没有直接回答你的问题,但我想提一下 Apple 最近有这个演讲:
https://developer.apple.com/videos/play/wwdc2018/714/
在 09:55 左右,他谈到了做你所询问的事情:
- 检查连接
- 如果连接 -> 做点什么
- 如果没有连接 -> 执行其他操作(等待?重试?)
但是,这有一些缺陷:
- 如果在第 2 步中它说它有连接,但 0.5 秒后他没有连接怎么办?
- 如果用户在代理后面怎么办
- 最后但同样重要的是,如果这里的某些答案无法确定连接正确怎么办? (我敢肯定,如果你快速切换你的连接,转到 wi-fi 并将其关闭(只是让它变得复杂),它几乎永远无法正确确定我是否有连接)。
- 引自视频:"There is no way to guarentee whether a future operation will succeed or not"
以下几点是 Apple 的一些最佳实践:
- 将
waitsForConnectivity
设置为真 (https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity)
- 响应委托方法
taskIsWaitingForConnectivity
(https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/2908819-urlsession)。这是 Apple 推荐的检查连接的方法,如 33:25. 的视频中所述
根据谈话,没有任何理由预先检查您是否有互联网连接,因为在您向服务器发送请求时它可能不准确.
这是我的版本。本质上它没有带来任何新东西。我把它绑定到 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}),
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" ))
Apple 在 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
}
}
虽然它可能无法直接确定 phone 是否已连接到网络,但最简单(最干净?)的解决方案是 'ping' Google 或其他服务器, (这是不可能的,除非 phone 连接到网络):
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 多台服务器,并 return 看看其中是否可以访问。或者让某人为此目的设置专用服务器。
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()
}
Swift 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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")
}
或者只需使用此 framework
更多 Utilities
:Link
iOS12 Swift 4 和 Swift 5
如果你只想检查连接,而你的最低目标是iOS12,那么你可以使用NWPathMonitor
import Network
它需要一些属性设置。
let internetMonitor = NWPathMonitor()
let internetQueue = DispatchQueue(label: "InternetMonitor")
private var hasConnectionPath = false
我创建了一个函数来让它运行。您可以在 view did load 或其他任何地方执行此操作。我放了一个守卫,所以你可以随心所欲地调用它。
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
}
现在你可以直接调用辅助函数hasInternet()
看看你有没有。它实时更新。请参阅 NWPathMonitor
的 Apple 文档。如果您需要停止跟踪连接、您正在寻找的互联网类型等,它还有更多功能,例如 cancel()
。
https://developer.apple.com/documentation/network/nwpathmonitor
这里是接受答案的相同代码,但我发现在某些情况下使用 closures
更有用
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) {
[=10=].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。将以下代码剪切并粘贴到其中以创建您的 class.
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) {
[=10=].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 使用 Combine 对 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 的可达性 class
https://github.com/ashleymills/Reachability.swift.
- 将可达性 class 添加到项目中。
- 将以下代码放入您的class维护连接状态
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
}
}
}
- 像下面这样使用它:
ConnectionManager.shared.hasConnectivity()
其中许多答案不再有效。
原因是使用了 vpn(因为电晕,我们现在通过 vpn 而不是公司 wifi 进行测试)
使用苹果的网络框架并基于此处找到的代码https://medium.com/@udaykiran.munaga/swift-check-for-internet-connectivity-14e355fa10c5我能够分别检测到 wifi 和蜂窝网络。由于使用 vpn,路径通常保持满意,因此对于 isConnectedToNetwork() 始终 return 为真。
下面是使用 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: 开始监控。
Reachability.shared.startMonitoring()
要在某个实例中检查互联网,可以使用 Swift 5
import Foundation
import Alamofire
struct NetworkState {
var isInternetAvailable:Bool
{
return NetworkReachabilityManager()!.isReachable
}
}
并通过以下方式使用它:
if (NetworkState().isInternetAvailable) {
//connected to internet
}
没有真正的方法可以做到这一点,即使是这样做的 API 也会尝试连接到特定服务,并在之前失败后告诉您它是否成功,最好的方法是尝试连接到您的服务,然后适当地处理错误,如果你想要一些服务在你连接时通知你,所有会发生的是它定期调用一个固定的服务直到它得到响应然后让你知道它成功了,如果问题怎么办不是互联网本身,而是您尝试连接的特定服务。
最好的方法是在你的连接方法中设计自己处理这个问题,你可以根据你的错误在给定的时间内触发重试,也许是失败的次数,你可以return 一个错误,您可以使用它来显示错误消息,让用户有可能再试一次,可能是尝试几次的组合,然后是 return 和错误。
另一个与此类似的问题是发送您已经发送但尚未收到回复的消息,再次最好只编写您的应用程序来处理此问题,忽略请求,直到它等待的请求 returned,如果请求不同则取消等待请求等
这些东西可以用非常通用的方式编写,因此它们可以用于您的应用程序甚至不同项目的许多不同方面。
Swift 5.5,iOS 12+,没有更多的 third-party 库。
请检查这个要点 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)
}
}
当我尝试检查我的 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([=11=]))
}
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
}
}
代码错误:
如果不可读,错误 1 表示:
'Int' is not convertible to 'SCNetworkReachabilityFlags'
错误 2 和 3:
Could not find an overload for 'init' that accepts the supplied arguments
为了解决评论中提到的 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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([=11=]))
} ? 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
。将以下代码剪切并粘贴到其中以创建您的 class.
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer([=10=]))
}
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")
}
如果用户未连接到 Internet,您可能希望向他们显示一个警告对话框以通知他们。
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()
}
解释:
我们正在制作一个可重复使用的 public class 和一个可以在项目中的任何地方使用的方法来检查互联网连接。我们需要添加基础和系统配置框架。
在 public class 可达性中,方法 isConnectedToNetwork() -> Bool { }
将 return 一个关于互联网连接的布尔值。我们使用 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
}
}
我已经检查了在没有 Cocoa Pods/Dependancy 管理器的情况下实施 Ashley Mill 的可达性 class。这个想法是使项目中的可达性依赖自由。
Xcode 7.2 - Swift 2.1
1) https://github.com/ashleymills/Reachability.swift。下载将 Reachability class 添加到项目中。
注意:添加时,请确保勾选'copy items if needed'。
2) 制作一个 AppManager.swift class 。此 class 将迎合 Public 模型 class,其中 public 方法和数据将被添加并可用于任何 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) 创建委托 Class。我使用委托方法来通知连接状态。
// Protocols.swift
import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {
func reachabilityStatusChangeHandler(reachability:Reachability)
}
4) 使 UIViewController 的父级 class(继承方法)。父 class 具有所有子 VC 都可以访问的方法。
// UIappViewController.swift
import UIKit
class UIappViewController: UIViewController,AppManagerDelegate {
var manager:AppManager = AppManager.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func reachabilityStatusChangeHandler(reachability: Reachability) {
if reachability.isReachable() {
print("isReachable")
} else {
print("notReachable")
}
}
}
5) 在 AppDelegate 中启动实时 Internet 连接监控。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
AppManager.sharedInstance.initRechabilityMonitor()
return true
}
6) 我添加了一个 Swift 文件名 AppReference 来存储常量枚举值。
// AppReference.swift
import Foundation
enum CONNECTION_NETWORK_TYPE : String {
case WIFI_NETWORK = "Wifi"
case WWAN_NETWORK = "Cellular"
case OTHER = "Other"
}
7) 在 ViewController 上(例如,您只想在网络可用时调用 API)
// ViewController.swift
import UIKit
class ViewController: UIappViewController {
var reachability:Reachability?
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
if(AppManager.sharedInstance.isReachability)
{
print("net available")
//call API from here.
} else {
dispatch_async(dispatch_get_main_queue()) {
print("net not available")
//Show Alert
}
}
//Determine Network Type
if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
{
print(".Wifi")
}
else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
{
print(".Cellular")
}
else {
dispatch_async(dispatch_get_main_queue()) {
print("Network not reachable")
}
}
}
override func viewWillAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
}
}
样本可以下载@https://github.com/alvinreuben/Reachability-Sample
升级到 Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3
如果你使用的是 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 作为 Reachability.swift,我创建了以下函数:
func hasConnectivity() -> Bool {
do {
let reachability: Reachability = try Reachability.reachabilityForInternetConnection()
let networkStatus: Int = reachability.currentReachabilityStatus.hashValue
return (networkStatus != 0)
}
catch {
// Handle error however you please
return false
}
}
只需在需要检查连接的地方调用 hasConnectivity()
。这适用于 Wifi 和蜂窝网络。
添加 ashleymills 的 Reachability.swift 这样人们就不必在站点之间移动:
Copyright (c) 2014, Ashley Mills
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Reachability.swift version 2.2beta2
import SystemConfiguration
import Foundation
public enum ReachabilityError: ErrorType {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
public let ReachabilityChangedNotification = "ReachabilityChangedNotification"
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
dispatch_async(dispatch_get_main_queue()) {
reachability.reachabilityChanged(flags)
}
}
public class Reachability: NSObject {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
public enum NetworkStatus: CustomStringConvertible {
case NotReachable, ReachableViaWiFi, ReachableViaWWAN
public var description: String {
switch self {
case .ReachableViaWWAN:
return "Cellular"
case .ReachableViaWiFi:
return "WiFi"
case .NotReachable:
return "No Connection"
}
}
}
// MARK: - *** Public properties ***
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
public var reachableOnWWAN: Bool
public var notificationCenter = NSNotificationCenter.defaultCenter()
public var currentReachabilityStatus: NetworkStatus {
if isReachable() {
if isReachableViaWiFi() {
return .ReachableViaWiFi
}
if isRunningOnDevice {
return .ReachableViaWWAN
}
}
return .NotReachable
}
public var currentReachabilityString: String {
return "\(currentReachabilityStatus)"
}
private var previousFlags: SCNetworkReachabilityFlags?
// MARK: - *** Initialisation methods ***
required public init(reachabilityRef: SCNetworkReachability) {
reachableOnWWAN = true
self.reachabilityRef = reachabilityRef
}
public convenience init(hostname: String) throws {
let nodename = (hostname as NSString).UTF8String
guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }
self.init(reachabilityRef: ref)
}
public class func reachabilityForInternetConnection() throws -> Reachability {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let ref = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer([=11=]))
}) 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([=11=]))
}) 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([=11=]))
}
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) {
[=10=].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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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 解决方案的可达性,因为它 returns "true" 如果有 WiFi 但没有互联网。因此,我通过 URLSession class 和完成处理程序实现了第二次验证。
这里是全文class。
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
[=10=].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")
}
虽然它没有直接回答你的问题,但我想提一下 Apple 最近有这个演讲:
https://developer.apple.com/videos/play/wwdc2018/714/
在 09:55 左右,他谈到了做你所询问的事情:
- 检查连接
- 如果连接 -> 做点什么
- 如果没有连接 -> 执行其他操作(等待?重试?)
但是,这有一些缺陷:
- 如果在第 2 步中它说它有连接,但 0.5 秒后他没有连接怎么办?
- 如果用户在代理后面怎么办
- 最后但同样重要的是,如果这里的某些答案无法确定连接正确怎么办? (我敢肯定,如果你快速切换你的连接,转到 wi-fi 并将其关闭(只是让它变得复杂),它几乎永远无法正确确定我是否有连接)。
- 引自视频:"There is no way to guarentee whether a future operation will succeed or not"
以下几点是 Apple 的一些最佳实践:
- 将
waitsForConnectivity
设置为真 (https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity) - 响应委托方法
taskIsWaitingForConnectivity
(https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/2908819-urlsession)。这是 Apple 推荐的检查连接的方法,如 33:25. 的视频中所述
根据谈话,没有任何理由预先检查您是否有互联网连接,因为在您向服务器发送请求时它可能不准确.
这是我的版本。本质上它没有带来任何新东西。我把它绑定到 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}),
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" ))
Apple 在 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
}
}
虽然它可能无法直接确定 phone 是否已连接到网络,但最简单(最干净?)的解决方案是 'ping' Google 或其他服务器, (这是不可能的,除非 phone 连接到网络):
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 多台服务器,并 return 看看其中是否可以访问。或者让某人为此目的设置专用服务器。
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()
}
Swift 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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, {
[=10=].withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, [=10=])
}
}) 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")
}
或者只需使用此 framework
更多 Utilities
:Link
iOS12 Swift 4 和 Swift 5
如果你只想检查连接,而你的最低目标是iOS12,那么你可以使用NWPathMonitor
import Network
它需要一些属性设置。
let internetMonitor = NWPathMonitor()
let internetQueue = DispatchQueue(label: "InternetMonitor")
private var hasConnectionPath = false
我创建了一个函数来让它运行。您可以在 view did load 或其他任何地方执行此操作。我放了一个守卫,所以你可以随心所欲地调用它。
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
}
现在你可以直接调用辅助函数hasInternet()
看看你有没有。它实时更新。请参阅 NWPathMonitor
的 Apple 文档。如果您需要停止跟踪连接、您正在寻找的互联网类型等,它还有更多功能,例如 cancel()
。
https://developer.apple.com/documentation/network/nwpathmonitor
这里是接受答案的相同代码,但我发现在某些情况下使用 closures
更有用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) {
[=10=].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。将以下代码剪切并粘贴到其中以创建您的 class.
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) {
[=10=].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 使用 Combine 对 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 的可达性 class https://github.com/ashleymills/Reachability.swift.
- 将可达性 class 添加到项目中。
- 将以下代码放入您的class维护连接状态
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
}
}
}
- 像下面这样使用它:
ConnectionManager.shared.hasConnectivity()
其中许多答案不再有效。
原因是使用了 vpn(因为电晕,我们现在通过 vpn 而不是公司 wifi 进行测试)
使用苹果的网络框架并基于此处找到的代码https://medium.com/@udaykiran.munaga/swift-check-for-internet-connectivity-14e355fa10c5我能够分别检测到 wifi 和蜂窝网络。由于使用 vpn,路径通常保持满意,因此对于 isConnectedToNetwork() 始终 return 为真。
下面是使用 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: 开始监控。
Reachability.shared.startMonitoring()
要在某个实例中检查互联网,可以使用 Swift 5
import Foundation
import Alamofire
struct NetworkState {
var isInternetAvailable:Bool
{
return NetworkReachabilityManager()!.isReachable
}
}
并通过以下方式使用它:
if (NetworkState().isInternetAvailable) {
//connected to internet
}
没有真正的方法可以做到这一点,即使是这样做的 API 也会尝试连接到特定服务,并在之前失败后告诉您它是否成功,最好的方法是尝试连接到您的服务,然后适当地处理错误,如果你想要一些服务在你连接时通知你,所有会发生的是它定期调用一个固定的服务直到它得到响应然后让你知道它成功了,如果问题怎么办不是互联网本身,而是您尝试连接的特定服务。
最好的方法是在你的连接方法中设计自己处理这个问题,你可以根据你的错误在给定的时间内触发重试,也许是失败的次数,你可以return 一个错误,您可以使用它来显示错误消息,让用户有可能再试一次,可能是尝试几次的组合,然后是 return 和错误。
另一个与此类似的问题是发送您已经发送但尚未收到回复的消息,再次最好只编写您的应用程序来处理此问题,忽略请求,直到它等待的请求 returned,如果请求不同则取消等待请求等
这些东西可以用非常通用的方式编写,因此它们可以用于您的应用程序甚至不同项目的许多不同方面。
Swift 5.5,iOS 12+,没有更多的 third-party 库。
请检查这个要点 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)
}
}