Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // Reachability.swift
- // TestReach
- //
- // Created by Pavel Hlavnicka on 02/12/2016.
- // Copyright © 2016 Pavel Hlavnicka. All rights reserved.
- //
- import Foundation
- import SystemConfiguration
- let ReachabilityDidChangeNotificationName = "ReachabilityDidChangeNotification"
- enum ReachabilityStatus {
- case notReachable
- case reachableViaWiFi
- case reachableViaWWAN
- }
- /* SIMPLER: no need to inherit from NSObject */
- //class Reachability: NSObject {
- class Reachability {
- private var networkReachability: SCNetworkReachability?
- init?(hostName: String) {
- networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, (hostName as NSString).utf8String!)
- //SIMPLER: no superclass
- //super.init()
- if networkReachability == nil {
- return nil
- }
- }
- init?(hostAddress: sockaddr_in) {
- /* SIMPLER: Swift has some buildins to solve this */
- /*
- var address = hostAddress
- guard let defaultRouteReachability = withUnsafePointer(to: &address, {
- $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
- SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
- }
- }) else {
- return nil
- }
- networkReachability = defaultRouteReachability
- */
- var address = unsafeBitCast(hostAddress, to: sockaddr.self)
- networkReachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, &address)
- //SIMPLER: no superclass
- //super.init()
- if networkReachability == nil {
- return nil
- }
- }
- deinit {
- stopNotifier()
- }
- class func networkReachabilityForInternetConnection() -> Reachability? {
- var zeroAddress = sockaddr_in()
- zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
- zeroAddress.sin_family = sa_family_t(AF_INET)
- return Reachability(hostAddress: zeroAddress)
- }
- class func networkReachabilityForLocalWiFi() -> Reachability? {
- var localWifiAddress = sockaddr_in()
- localWifiAddress.sin_len = UInt8(MemoryLayout.size(ofValue: localWifiAddress))
- localWifiAddress.sin_family = sa_family_t(AF_INET)
- // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0 (0xA9FE0000).
- localWifiAddress.sin_addr.s_addr = 0xA9FE0000
- return Reachability(hostAddress: localWifiAddress)
- }
- private var notifying: Bool = false
- func startNotifier() -> Bool {
- guard notifying == false else {
- return false
- }
- var context = SCNetworkReachabilityContext()
- //SIMPLER: I believe calling an initializer is redundant
- //context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
- context.info = Unmanaged.passUnretained(self).toOpaque()
- //SIMPLER: I believe the below can be simplified as we are quite sure about the context.info type
- //though there are never enough paranoia checks ;)
- /*
- guard let reachability = networkReachability, SCNetworkReachabilitySetCallback(reachability, { (target: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) in
- if let currentInfo = info {
- let infoObject = Unmanaged<AnyObject>.fromOpaque(currentInfo).takeUnretainedValue()
- if infoObject is Reachability {
- let networkReachability = infoObject as! Reachability
- NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityDidChangeNotificationName), object: networkReachability)
- }
- }
- }, &context) == true else { return false }
- */
- guard let reachability = networkReachability, SCNetworkReachabilitySetCallback(reachability, { (target: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) in
- if let currentInfo = info {
- let callbackSelf = Unmanaged<Reachability>.fromOpaque(currentInfo).takeUnretainedValue()
- NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityDidChangeNotificationName), object: callbackSelf)
- }
- }, &context) else { return false }
- //SIMPLER: == true checks are killing kittens ;)
- /*
- guard SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) == true else { return false }
- */
- guard SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) else { return false }
- notifying = true
- return notifying
- }
- func stopNotifier() {
- if let reachability = networkReachability, notifying == true {
- SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode as! CFString)
- notifying = false
- }
- }
- private var flags: SCNetworkReachabilityFlags {
- var flags = SCNetworkReachabilityFlags(rawValue: 0)
- //SIMPLER: again Swift makes bridging a bit easier
- /*
- if let reachability = networkReachability, withUnsafeMutablePointer(to: &flags, { SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0)) }) == true {
- return flags
- }
- else {
- return []
- }
- */
- if let reachability = networkReachability, SCNetworkReachabilityGetFlags(reachability, &flags) {
- return flags
- } else {
- return []
- }
- }
- var currentReachabilityStatus: ReachabilityStatus {
- 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
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement