代码:
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(q4312078q))
}
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'不能转换为'SCNetworkReachabilityFlags'
错误2和3:
无法找到接受提供的参数的'init'的重载
#1 楼
为了解决注释中提到的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, {
extension Reachability {
func start() throws {
guard let reachability = reachability, !isRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
throw Network.Error.failedToSetCallout
}
guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
throw Network.Error.failedToSetDispatchQueue
}
reachabilitySerialQueue.async { self.flagsChanged() }
isRunning = true
}
func stop() {
defer { isRunning = false }
guard let reachability = reachability else { return }
SCNetworkReachabilitySetCallback(reachability, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachability, nil)
self.reachability = nil
}
var isConnectedToNetwork: Bool {
return isReachable &&
!isConnectionRequiredAndTransientConnection &&
!(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
}
var isReachableViaWiFi: Bool {
return isReachable && isRunningOnDevice && !isWWAN
}
/// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
var flags: SCNetworkReachabilityFlags? {
guard let reachability = reachability else { return nil }
var flags = SCNetworkReachabilityFlags()
return withUnsafeMutablePointer(to: &flags) {
SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer(func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
DispatchQueue.main.async {
Unmanaged<Reachability>
.fromOpaque(info)
.takeUnretainedValue()
.flagsChanged()
}
}
))
} ? flags : nil
}
/// compares the current flags with the previous flags and if changed posts a flagsChanged notification
func flagsChanged() {
guard let flags = flags, flags != reachabilityFlags else { return }
reachabilityFlags = flags
NotificationCenter.default.post(name: .flagsChanged, object: self)
}
/// The specified node name or address can be reached via a transient connection, such as PPP.
var transientConnection: Bool { return flags?.contains(.transientConnection) == true }
/// The specified node name or address can be reached using the current network configuration.
var isReachable: Bool { return flags?.contains(.reachable) == true }
/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }
/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }
/// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }
/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }
/// The specified node name or address is one that is associated with a network interface on the current system.
var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }
/// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
var isDirect: Bool { return flags?.contains(.isDirect) == true }
/// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
var isWWAN: Bool { return flags?.contains(.isWWAN) == true }
/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
/// The specified node name or address can be reached via a transient connection, such as PPP.
var isConnectionRequiredAndTransientConnection: Bool {
return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
}
}
.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, extension Notification.Name {
static let flagsChanged = Notification.Name("FlagsChanged")
}
)
}
}) else {
throw Network.Error.failedToInitializeWith(zeroAddress)
}
self.reachability = reachability
isReachableOnWWAN = true
try start()
}
var status: Network.Status {
return !isConnectedToNetwork ? .unreachable :
isReachableViaWiFi ? .wifi :
isRunningOnDevice ? .wwan : .unreachable
}
var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
deinit { stop() }
}
struct Network {
static var reachability: Reachability!
enum Status: String {
case unreachable, wifi, wwan
}
enum Error: Swift.Error {
case failedToSetCallout
case failedToSetDispatchQueue
case failedToCreateWith(String)
case failedToInitializeWith(sockaddr_in)
}
}
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
do {
try Network.reachability = Reachability(hostname: "www.google.com")
}
catch {
switch error as? Network.Error {
case let .failedToCreateWith(hostname)?:
print("Network error:\nFailed to create reachability object With host named:", hostname)
case let .failedToInitializeWith(address)?:
print("Network error:\nFailed to initialize reachability object With address:", address)
case .failedToSetCallout?:
print("Network error:\nFailed to set callout")
case .failedToSetDispatchQueue?:
print("Network error:\nFailed to set DispatchQueue")
case .none:
print(error)
}
}
return true
}
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.addObserver(self,
selector: #selector(statusManager),
name: .flagsChanged,
object: nil)
updateUserInterface()
}
func updateUserInterface() {
switch Network.reachability.status {
case .unreachable:
view.backgroundColor = .red
case .wwan:
view.backgroundColor = .yellow
case .wifi:
view.backgroundColor = .green
}
print("Reachability Summary")
print("Status:", Network.reachability.status)
print("HostName:", Network.reachability.hostname ?? "nil")
print("Reachable:", Network.reachability.isReachable)
print("Wifi:", Network.reachability.isReachableViaWiFi)
}
@objc func statusManager(_ notification: Notification) {
updateUserInterface()
}
}
q4312078q
用法
在AppDelegate中初始化它。swed didFinishLaunchingWithOptions方法并处理可能发生的任何错误:
q4312078q
和视图控制器示例:
q4312078q
样本项目
评论
您需要从if SCNetworkReachabilityGetFlags(…)中删除`== 0',因为xCode返回了最新版本的Bool。
–梅尔文
2015年9月11日在2:42
如@NickM所述,这是不正确的。对于蜂窝连接将不起作用。不要使用这个。我很惊讶它获得了如此多的赞成票,也许这是iOS 9以来的新功能……但是我不这么认为。
–乔丹·史密斯
16-3-3在3:33
在IOS9上不起作用,发现了非常困难的方法-商店中的应用程序...因此,我猜即使它不是100%准确并且适用于某些应用程序,它充其量也是不一致的,所以任何想冒险的人都可能想要如果他们感到幸运,可以赌一些马或狗。
–尼克M
16 Mar 3 '16 at 10:36
@NickM-解释了为什么这么多的投票。 @ Leo,更新您的iOS 9答案可能是个好主意,以免其他人陷入同一陷阱。我可以确认它(至少在某些情况下)在iOS 9上不起作用...更改为github.com/ashleymills/Reachability.swift可以正常工作。
–乔丹·史密斯
16 Mar 3 '16 at 11:27
是的,我看到它正在iOS10分支中取出
–王牌绿色
16年8月19日在1:00
#2 楼
对于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) {
if Reachability.isConnectedToNetwork(){
print("Internet Connection Available!")
}else{
print("Internet Connection not Available!")
}
.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
return false
}
/* Only Working for WIFI
let isReachable = flags == .reachable
let needsConnection = flags == .connectionRequired
return isReachable && !needsConnection
*/
// Working for Cellular and WIFI
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
let ret = (isReachable && !needsConnection)
return ret
}
}
用法:
q4312078q
评论
此解决方案+ CoreTelephony(CTTelephonyNetworkInfo()。currentRadioAccessTechnology)是获取当前网络类型的最佳解决方案,而无需依赖第三方库。
–亚历杭德罗(AlejandroJiménez)Agudo
16-10-23在18:13
可以通过3.1快速用于蜂窝和WiFi!在iPhone 6和iPhone 7上进行了测试。如果“蜂窝关闭”,则显示“ ..Connection不可用”。如果我开启飞行模式,则得到相同的“ ...不可用”。如果我关闭蜂窝并打开wifi,我会收到“ .. Connection Available”,最后,如果我关闭wifi并打开Cellular,我会收到“ .. Connection Available”。注意我的蜂窝连接是LTE
–布赖恩
17年4月10日在22:34
嗨,这在物理设备上的iOS 11,飞机模式下不起作用。当设置为飞行模式时,isReachable仍然为true ...知道为什么吗?
–劳伦斯·谭(Lawrence Tan)
18年1月16日在7:57
在所有情况下,这对我来说都是完美的。它还已经在iPhone 6上运行的iOS 12上进行了测试。
–r3dm4n
18年6月26日在16:47
如果我没有网络连接就连接到wifi网络,则无法使用
–内森·巴雷托(Nathan Barreto)
18年7月10日在19:35
#3 楼
如果有人已经在使用Alamofire,则-struct Connectivity {
static let sharedInstance = NetworkReachabilityManager()!
static var isConnectedToInternet:Bool {
return self.sharedInstance.isReachable
}
}
if Connectivity.isConnectedToInternet {
print("Connected")
} else {
print("No Internet")
}
评论
从Alamofire文档中:> NetworkReachabilityManager类侦听WWAN和WiFi网络接口的主机和地址的可达性更改。 >可达性可用于确定有关网络操作失败原因的背景信息,或在建立连接时重试网络请求。它不应用于阻止用户发起网络请求,因为可能需要初始请求才能建立可达性。
– fespinozacast
18年5月28日在12:46
@fespinozacast好,您可以在NetworkReachabilityManager.swift中检查互联网连接代码,这完全可以:)
–杰克
18年7月26日在11:10
最好的解决方案!谢谢!
–VyacheslavBakinkskiy
12月4日6:44
#4 楼
在您的项目中创建一个新的Swift文件,将其命名为Reachability.swift
。将以下代码剪切并粘贴到其中以创建您的类。import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer(if Reachability.isConnectedToNetwork() {
println("Internet connection OK")
} else {
println("Internet connection FAILED")
}
))
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
return false
}
let isReachable = flags == .Reachable
let needsConnection = flags == .ConnectionRequired
return isReachable && !needsConnection
}
}
您可以使用以下代码在项目中的任何位置检查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()
}
如果用户未连接到Internet,则可能希望向他们显示警报对话框以通知他们。
q4312078q
说明:
我们正在制作可重用的公共类和一种可在项目中的任何地方用于检查Internet连接的方法。我们需要添加基础和系统配置框架。
在公共类可达性中,方法
isConnectedToNetwork() -> Bool { }
将返回有关Internet连接的布尔值。我们使用if循环对大小写执行所需的操作。我希望这足够了。干杯!评论
提供解决方案时,请尝试说明一下。提供解决方案并不重要,但让读者理解解决方案及其概念更为重要。
–G.Abhisek
2015年12月15日5:44
我是iOS编程的新手。为什么我们需要为此初始化C结构。在哪些情况下可以使用C结构?
–G.Abhisek
15年12月15日在6:08
我把它放在“ viewdidload”上只是为了测试。我打开应用程序,然后确定,可以连接互联网,但是当我断开互联网连接时,它继续显示我可以连接互联网...这是持久的吗?还是我每次都要“行动起来”?
–丹尼尔·阿兰特斯·洛弗德(Daniel Arantes Loverde)
16-2-15在18:19
@AlvinGeorge在连接到蜂窝网络时不起作用。仅在使用wifi时有效。对于其他任何人-您不想在您的应用程序中使用它! @ Alvin-我可以建议您更新或删除答案吗?如果获得19票赞成,这很可能会误导其他可能陷入同一陷阱的开发人员。
–乔丹·史密斯
16 Mar 2 '16 at 20:16
@Jordan:此方法使用默认的Apple框架获取网络状态。新的iOS版本可能会更改。因此,我建议您检查并实施Ashely Mill的可达性课程。我已经完成了无依赖项的实现,并共享了上面的链接。请看一看。
– A.G
16-3-3在6:35
#5 楼
我已经签出了在没有Cocoa Pods / Dependency Manager的情况下实现Ashley Mill的可达性类的方法。想法是使项目中的可达性依赖项自由。Xcode 7.2-Swift 2.1
1)https://github.com/ashleymills/Reachability.swift。下载将Reachability类添加到项目中。
注意:添加时,请确保选中“如果需要,则复制项目”。
2)创建一个AppManager.swift类。该类将作为Public Model类,其中将添加公共方法和数据,并且可以在任何VC中使用。
3)创建一个委托类。我使用委托方法来通知连接状态。
// 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)
}
}
}
4)设置UIViewController的父类(继承方法)。父类具有所有子VC均可访问的方法。
// Protocols.swift
import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {
func reachabilityStatusChangeHandler(reachability:Reachability)
}
5)在AppDelegate中开始实时Internet连接监视。
// 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")
}
}
}
6)我添加了一个Swift文件名AppReference来存储常量枚举值。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
AppManager.sharedInstance.initRechabilityMonitor()
return true
}
7)在ViewController上(例如,仅当网络可用时,您才想调用API)
// AppReference.swift
import Foundation
enum CONNECTION_NETWORK_TYPE : String {
case WIFI_NETWORK = "Wifi"
case WWAN_NETWORK = "Cellular"
case OTHER = "Other"
}
可以下载该示例@ https://github.com/alvinreuben/Reachability-Sample
升级到Swift 3.1-
https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3
评论
在步骤4 ... UIappViewController.swift中,为什么我们需要这个类!
–Learn2Code
17年4月1日在23:52
UIappViewController.swift不能与UICollectionViewController一起使用,因此,如果您有一个UICollectionViewController的视图,则不能继承UIappViewController !?
–Learn2Code
17年4月1日在23:54
#6 楼
Apple已在iOS12中引入了Network Framework。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
}
}
评论
var路径:NWPath?是零。我们如何初始化该属性?
– Vitya Shurapov
19年5月6日在10:24
@VityaShurapov通过分配路径,您将进入pathUpdateHandler块。
– Yogendra Singh
19年5月7日10:00
这看起来很不错,但是我发现(至少在模拟器上)如果我关闭笔记本电脑的wifi然后再打开,我会收到一个回调,但它说“不满意”,此后再也不会调用该回调。
– Zaitsman
19年5月22日在7:27
当蜂窝周期开/关时,处理程序仅触发一次开/关。 WiFi开启/关闭时,我会得到2个相同的开启/关闭触发器(所有属性都相同)。这是为什么?
–geohei
19年7月12日在14:09
pathUpdateHandler将引入一个带有self的强引用,添加[weak self]可以解决它:)
– Andrea de Marco
19-10-11在20:54
#7 楼
尽管它不能直接回答您的问题,但我想提一下Apple最近在这里进行的演讲:https://developer.apple.com/videos/play/wwdc2018/714/
在09:55左右,他谈论您正在询问的事情:
检查连接
如果连接->做某事
如果没有连接->做其他事情(等待吗?重试?)
但是,这有一些陷阱:
如果在第2步中说它有一个连接,但0.5秒后又没有连接?
最后但并非最不重要的是,如果用户在代理后面,该怎么办?如果此处的某些答案不能确定连接正确,该怎么办? (我敢肯定,如果您快速切换连接,转到wi-fi并将其关闭(只是使其变得复杂),无论我是否获得连接,它几乎都无法正确确定)。
视频:“无法确保将来的操作是否成功”
以下几点是苹果公司的一些最佳做法:
将
waitsForConnectivity
设置为true(https://developer.apple.com/documentation/foundation/urlsessionconfiguration/2908812-waitsforconnectivity)响应委托方法
taskIsWaitingForConnectivity
(https://developer.apple.com/documentation / foundation / urlsessiontaskdelegate / 2908819-urlsession)。如视频中33:25所述,这是苹果公司推荐的检查连接的方法。根据谈话,如果您有互联网连接或否,因为在您将请求发送到服务器时可能不准确。
#8 楼
将其用于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, {
if InternetConnectionManager.isConnectedToNetwork(){
print("Connected")
}else{
print("Not Connected")
}
.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, q4312078q)
}
}) 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)
}
}
q4312078q
,或仅将
framework
用于更多Utilities
:链接评论
@ DocAsh59 :)欢迎光临!编码愉快!
–贾米尔·哈斯宁·塔米姆(Jamil Hasnine Tamim)
2月17日12:45
我不明白它的用法。编译器显示错误“传递给调用的参数不带参数”。
–罗兰·拉里奥特(Roland Lariotte)
5月15日21:33
@RolandLariotte您只需在名为“ InternetConnectionManager”的项目中进行分类,然后从所需位置进行调用!
–贾米尔·哈斯宁·塔米姆(Jamil Hasnine Tamim)
5月17日4:15
完美运作。您认为通过使用Combine并返回AnyPublisher
–罗兰·拉里奥特(Roland Lariotte)
5月17日5:14
@RolandLariotte是的。稍后我将编写另一个代码。谢谢,别忘了支持! :)
–贾米尔·哈斯宁·塔米姆(Jamil Hasnine Tamim)
5月20日8:14
#9 楼
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()
。 添加ashleymills的Reachability.sift,使人们不必在站点之间移动:
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(q4312078q))
}) 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(q4312078q))
}) 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(q4312078q))
}
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
}
}
评论
@ Xitcod13这将适用于4G网络。话虽如此,建议不要测试飞行前。处理尝试连接时引发的异常,而不要使用Reachability.swift测试用例。
– cmeadows
16年8月23日在15:51
swift3的github.com/justin/Reachability.swift/tree/feature/swift3.0
– AMAN77
16-10-5在9:35
Reachability.swift遇到Swift 3问题
–专业技术
16 Dec 24'在5:27
与Swift 3配合使用时,只需更改let可达性即可:Reachability =试试Reachability.reachabilityForInternetConnection()来让可达性:Reachability =试试Reachability()!
– davidethell
17年3月14日在11:34
#10 楼
我已经使用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
}
}
评论
如果网站服务器已关闭怎么办?
– TechBee
16年2月2日,12:17
然后在达到指定的超时时间后将调用requestTimeout()
– Mark Tickner
16年2月2日,12:21
谢谢马克!您的方法应该是通用的!!
– TechBee
16年2月2日,12:27
用什么方式?使用的网站?想法是使用的网站是您的应用程序所依赖的网站
– Mark Tickner
16年2月2日在14:21
@ GoodSp33d此方法非常适合检查Web服务是否正在运行。您可能具有Internet连接,但是如果Web服务关闭,则可能希望允许该应用程序表现为好像它们没有网络连接(例如,脱机工作)。
–科林·巴尼斯(Colin Basnett)
16年7月8日在19:48
#11 楼
如果您使用的是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
}
}
#12 楼
虽然它可能无法直接确定电话是否已连接到网络,但最简单(最干净?)的解决方案是“ ping” Google或其他服务器(除非电话已连接到网络,否则这是不可能的) ):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操作,并返回是否他们是可以到达的。或者让某人为此专门设置专用服务器。
#13 楼
iOS12 Swift 4和Swift 5如果您只想检查连接,并且最低目标是iOS12,则可以使用
NWPathMonitor
import Network
它需要一些特性的小设置。
let internetMonitor = NWPathMonitor()
let internetQueue = DispatchQueue(label: "InternetMonitor")
private var hasConnectionPath = false
我创建了一个函数来实现它。您可以在视图加载后或在其他任何位置执行此操作。我放了一个警卫,以便您可以随心所欲地调用它。
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()
来查看是否有它。它实时更新。请参阅Apple文档以获取有关NWPathMonitor
的信息。它具有更多功能,例如cancel()
(如果您需要停止跟踪连接,正在寻找的Internet类型等)。https://developer.apple.com/documentation/network/nwpathmonitor
#14 楼
Swift 5import 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, {
if currentReachabilityStatus == .notReachable {
// Network Unavailable
} else {
// Network Available
}
.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, q4312078q)
}
}) 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
}
}
}
以任何方式使用以下条件
q4312078q
评论
它不适用于iOS 14及更高版本中的移动数据。
– Dharmendra Kumar Rajan
9月27日13:16
#15 楼
这是我使用lib(Reachability.swift)的Swift 2.3解决方案。进入您的
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
}
然后,当您要检查设备是否已连接到Internet时,请执行以下操作:
if ReachabilityManager.sharedInstance.isConnectedToNetwork() {
// Connected
} else {
// Not connected
}
#16 楼
对于Swift 3,我不能仅使用RAJAMOHAN-S解决方案的可达性,因为如果有WiFi但没有Internet,它将返回“ true”。因此,我通过URLSession类和完成处理程序实现了第二次验证。这里是全班。
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
Reachability.isInternetAvailable(webSiteToPing: nil) { (isInternetAvailable) in
guard isInternetAvailable else {
// Inform user for example
return
}
// Do some action if there is Internet
}
.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()
}
}
您这样称呼,例如:
q4312078q
#17 楼
如果您的项目目标高于或等于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)
}
}
只需订阅要关注的变量,您应该进行任何更改的更新。
#18 楼
借助以下代码,您可以检查蜂窝网络和wifi的Internet连接。语言-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, {
q4312078q.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, q4312078q)
}
}) 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
}
}
}
#19 楼
从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
}
#20 楼
在您的项目中创建一个新的Swift文件,将其命名为Reachability.swift。剪切并粘贴以下代码以创建您的类。import Foundation
import SystemConfiguration
open class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
if Reachability.isConnectedToNetwork() {
print("Network is connected")
} else {
print("Network is not connected")
}
.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)
}
}
您可以从代码的任何位置调用可达性,就像
q4312078q
#21 楼
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()
}
#22 楼
使用Combine的@martin的Swift 5+答案的更新版本。这还包括针对iOS 14的不可用性原因检查。import Combine
import Network
enum NetworkType {
case wifi
case cellular
case loopBack
case wired
case other
}
final class ReachabilityService: ObservableObject {
@Published var reachabilityInfos: NWPath?
@Published var isNetworkAvailable: Bool?
@Published var typeOfCurrentConnection: NetworkType?
private let monitor = NWPathMonitor()
private let backgroundQueue = DispatchQueue.global(qos: .background)
init() {
setUp()
}
init(with interFaceType: NWInterface.InterfaceType) {
setUp()
}
deinit {
monitor.cancel()
}
}
private extension ReachabilityService {
func setUp() {
monitor.pathUpdateHandler = { [weak self] path in
self?.reachabilityInfos = path
switch path.status {
case .satisfied:
print("ReachabilityService: satisfied")
self?.isNetworkAvailable = true
break
case .unsatisfied:
print("ReachabilityService: unsatisfied")
if #available(iOS 14.2, *) {
switch path.unsatisfiedReason {
case .notAvailable:
print("ReachabilityService: unsatisfiedReason: notAvailable")
break
case .cellularDenied:
print("ReachabilityService: unsatisfiedReason: cellularDenied")
break
case .wifiDenied:
print("ReachabilityService: unsatisfiedReason: wifiDenied")
break
case .localNetworkDenied:
print("ReachabilityService: unsatisfiedReason: localNetworkDenied")
break
@unknown default:
print("ReachabilityService: unsatisfiedReason: default")
}
} else {
// Fallback on earlier versions
}
self?.isNetworkAvailable = false
break
case .requiresConnection:
print("ReachabilityService: requiresConnection")
self?.isNetworkAvailable = false
break
@unknown default:
print("ReachabilityService: default")
self?.isNetworkAvailable = false
}
if path.usesInterfaceType(.wifi) {
self?.typeOfCurrentConnection = .wifi
} else if path.usesInterfaceType(.cellular) {
self?.typeOfCurrentConnection = .cellular
} else if path.usesInterfaceType(.loopback) {
self?.typeOfCurrentConnection = .loopBack
} else if path.usesInterfaceType(.wiredEthernet) {
self?.typeOfCurrentConnection = .wired
} else if path.usesInterfaceType(.other) {
self?.typeOfCurrentConnection = .other
}
}
monitor.start(queue: backgroundQueue)
}
}
在您的视图模型中:
private let reachability = ReachabilityService()
init() {
reachability.$isNetworkAvailable.sink { [weak self] isConnected in
self?.isConnected = isConnected ?? false
}.store(in: &cancelBag)
}
在您的控制器中:
viewModel.$isConnected.sink { [weak self] isConnected in
print("isConnected: \(isConnected)")
DispatchQueue.main.async {
//Update your UI in here
}
}.store(in: &bindings)
#23 楼
这是我的版本。从本质上讲,它并没有带来任何新的东西。我将其绑定到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, {
q4312078q.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, q4312078q)
}
}),
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" ))
评论
它不适用于iOS 14及更高版本中的移动数据。
– Dharmendra Kumar Rajan
9月27日13:23
#24 楼
这是具有可接受答案的相同代码,但是我发现在某些情况下使用闭包更有用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) {
Reachability.isConnectedToNetwork { (isConnected) in
if isConnected {
//We have internet connection | get data from server
} else {
//We don't have internet connection | load from database
}
}
.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)
}
}
这是使用方法:
q4312078q
评论
它不适用于iOS 14及更高版本中的移动数据。
– Dharmendra Kumar Rajan
9月27日13:23
评论
该代码看起来类似于我在这里建议的代码:stackoverflow.com/a/25623647/1187415,所以我已经为Swift 2更新了该代码。我在这里有一个可以正常工作的Swift 2 Reachability实现…github.com/ashleymills/Reachability.swift-随时使用它作为参考。
stackoverflow.com/a/25623647/1187415现在已为Swift 3,Xcode 8 beta 6更新。
Apple提供了一个正式的Swift样本,您可以在CocoaPods上获得它。它与任何Swift项目兼容。
stackoverflow.com/a/42710600/6898523或stackoverflow.com/a/43801932/6898523