一、NetworkReachabilityManager使用
//AppDelegate
let networkManager = NetworkReachabilityManager(host: "www.apple.com")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
/// 网络监控
networkManager!.listener = {
status in
var message = ""
switch status {
case .unknown:
message = "未知网络,请检查..."
case .notReachable:
message = "无法连接网络,请检查..."
case .reachable(.wwan):
message = "蜂窝移动网络,注意节省流量..."
case .reachable(.ethernetOrWiFi):
message = "WIFI-网络,使劲造吧..."
}
print("*******\(message)*******")
let alertVC = UIAlertController(title: "网络状况提示", message: message, preferredStyle: .alert)
alertVC.addAction(UIAlertAction(title: "我知道了", style: .default, handler: nil))
self.window?.rootViewController?.present(alertVC, animated: true, completion: nil)
}
networkManager!.startListening()
return true
}
class ViewController: UIViewController {
let urlString = "http://www.douban.com/j/app/radio/channels"
let urlDownloadStr = "https://www.baidu.com"
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(urlString).response { (respose) in
print("请求回调:\(respose)")
}
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
Alamofire.request(urlDownloadStr).response { (respose) in
print("请求回调:\(respose)")
if let error = respose.error as NSError?,error.code == -1009{
print("无网络状态,请弹框...")
let alertVC = UIAlertController(title: "无法连接网络", message: "确认网络连接无误,点击\"设置\"打开网络授权", preferredStyle: .alert)
let settingAction = UIAlertAction(title: "设置", style: .default, handler: { (action) in
if let url = URL(string: UIApplication.openSettingsURLString),UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
})
alertVC.addAction(UIAlertAction(title: "我知道了", style: .destructive, handler: nil))
alertVC.addAction(settingAction)
UIApplication.shared.delegate?.window??.rootViewController?.present(alertVC, animated: true, completion: nil)
}
}
}
}
二、源码解析
步骤一
- 点击
NetworkReachabilityManager(host: "www.apple.com")
-
SCNetworkReachabilityCreateWithName
iOS系统方法
public convenience init?(host: String) {
guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil }
self.init(reachability: reachability)
}
- 点击
self.init(reachability: reachability)
self.reachability = reachability
self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30)
private init(reachability: SCNetworkReachability) {
self.reachability = reachability
// Set the previous flags to an unreserved value to represent unknown status
self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30)
}
-
SCNetworkReachability
iOS系统类
public class SCNetworkReachability {
}
-
SCNetworkReachabilityFlags
iOS系统结构体
public struct SCNetworkReachabilityFlags : OptionSet {
public init(rawValue: UInt32)
public static var transientConnection: SCNetworkReachabilityFlags { get }
public static var reachable: SCNetworkReachabilityFlags { get }
public static var connectionRequired: SCNetworkReachabilityFlags { get }
public static var connectionOnTraffic: SCNetworkReachabilityFlags { get }
public static var interventionRequired: SCNetworkReachabilityFlags { get }
@available(iOS 3.0, *)
public static var connectionOnDemand: SCNetworkReachabilityFlags { get }
public static var isLocalAddress: SCNetworkReachabilityFlags { get }
public static var isDirect: SCNetworkReachabilityFlags { get }
@available(iOS 2.0, *)
public static var isWWAN: SCNetworkReachabilityFlags { get }
public static var connectionAutomatic: SCNetworkReachabilityFlags { get }
}
步骤二、保存闭包
- 点击
listener
open var listener: Listener?
public typealias Listener = (NetworkReachabilityStatus) -> Void
public enum NetworkReachabilityStatus {
case unknown
case notReachable
case reachable(ConnectionType)
}
public enum ConnectionType {
case ethernetOrWiFi
case wwan
}
步骤三
@discardableResult
open func startListening() -> Bool {
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = Unmanaged.passUnretained(self).toOpaque()
let callbackEnabled = SCNetworkReachabilitySetCallback(
reachability,
{ (_, flags, info) in
let reachability = Unmanaged.fromOpaque(info!).takeUnretainedValue()
reachability.notifyListener(flags)
},
&context
)
let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue)
listenerQueue.async {
guard let flags = self.flags else { return }
self.notifyListener(flags)
}
return callbackEnabled && queueEnabled
}
- 点击
self.notifyListener(flags)
-
listener?(networkReachabilityStatusForFlags(flags))
执行闭包
func notifyListener(_ flags: SCNetworkReachabilityFlags) {
guard previousFlags != flags else { return }
previousFlags = flags
listener?(networkReachabilityStatusForFlags(flags))
}
- 点击
networkReachabilityStatusForFlags
func networkReachabilityStatusForFlags(_ flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus {
guard isNetworkReachable(with: flags) else { return .notReachable }
var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi)
#if os(iOS)
if flags.contains(.isWWAN) { networkStatus = .reachable(.wwan) }
#endif
return networkStatus
}