Prashant Ghimire
Prashant Ghimire

Reputation: 548

Check internet connectivity throughout the app by adding observer

I do not want to check internet connectivity on every time the app is open instead want to show the no connection banner in status bar or in navigation bar just like the Facebook app does. Here is my code:

import SystemConfiguration

 public class Reachability {
class func isConnectedToNetwork() -> Bool {
    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)
    let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    }
    var flags = SCNetworkReachabilityFlags()
    if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
        return false
    }
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
}
}

Upvotes: 2

Views: 1246

Answers (2)

Nakul Sudhakar
Nakul Sudhakar

Reputation: 1594

Creating a notificationc object to help notif the app when a change in connectivity is encountered

var reach: Reachability!
    do {
        reach = try Reachability.reachabilityForInternetConnection()        
        self.reach!.reachableOnWWAN = false


        NSNotificationCenter.defaultCenter().addObserver(self,
                    selector: "reachabilityChanged:",
                    name: ReachabilityChangedNotification,
                    object: nil)

                try self.reach!.startNotifier()
            } catch {



            }

and the function based on which the app behaves

func reachabilityChanged(notification: NSNotification) {
        if self.reach!.isReachableViaWiFi() || self.reach!.isReachableViaWWAN() {

            print("Service available !!!")

        } else {

            print("No service available !!!")
        }
    } 

And use this Reachability class

    import Foundation

import SystemConfiguration
import Foundation

public enum ReachabilityError: ErrorType {
    case FailedToCreateWithAddress(sockaddr_in)
    case FailedToCreateWithHostname(String)
    case UnableToSetCallback
    case UnableToSetDispatchQueue
}

public let ReachabilityChangedNotification = "ReachabilityChangedNotification"

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
    let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

    dispatch_async(dispatch_get_main_queue()) {
        reachability.reachabilityChanged(flags)
    }
}


    public class Reachability: NSObject {

        public typealias NetworkReachable = (Reachability) -> ()
        public typealias NetworkUnreachable = (Reachability) -> ()

        public enum NetworkStatus: CustomStringConvertible {

            case NotReachable, ReachableViaWiFi, ReachableViaWWAN

            public var description: String {
                switch self {
                case .ReachableViaWWAN:
                    return "Cellular"
                case .ReachableViaWiFi:
                    return "WiFi"
                case .NotReachable:
                    return "No Connection"
                }
            }
        }

        // MARK: - *** Public properties ***
        public var whenReachable: NetworkReachable?
        public var whenUnreachable: NetworkUnreachable?
        public var reachableOnWWAN: Bool
        public var notificationCenter = NSNotificationCenter.defaultCenter()

        public var currentReachabilityStatus: NetworkStatus {
            if isReachable() {
                if isReachableViaWiFi() {
                    return .ReachableViaWiFi
                }
                if isRunningOnDevice {
                    return .ReachableViaWWAN
                }
            }
            return .NotReachable
        }

        public var currentReachabilityString: String {
            return "\(currentReachabilityStatus)"
        }

        private var previousFlags: SCNetworkReachabilityFlags?

        // MARK: - *** Initialisation methods ***

        required public init(reachabilityRef: SCNetworkReachability) {
            reachableOnWWAN = true
            self.reachabilityRef = reachabilityRef
        }

        public convenience init(hostname: String) throws {

            let nodename = (hostname as NSString).UTF8String
            guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }

            self.init(reachabilityRef: ref)
        }

        public class func reachabilityForInternetConnection() throws -> Reachability {

            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)

            guard let ref = withUnsafePointer(&zeroAddress, {
                SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
            }) else { throw ReachabilityError.FailedToCreateWithAddress(zeroAddress) }

            return Reachability(reachabilityRef: ref)
        }

        public class func reachabilityForLocalWiFi() throws -> Reachability {

            var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
            localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
            localWifiAddress.sin_family = sa_family_t(AF_INET)

            // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
            let address: UInt32 = 0xA9FE0000
            localWifiAddress.sin_addr.s_addr = in_addr_t(address.bigEndian)

            guard let ref = withUnsafePointer(&localWifiAddress, {
                SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
            }) else { throw ReachabilityError.FailedToCreateWithAddress(localWifiAddress) }

            return Reachability(reachabilityRef: ref)
        }

        // MARK: - *** Notifier methods ***
        public func startNotifier() throws {

            guard !notifierRunning else { return }

            var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
            context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())

            if !SCNetworkReachabilitySetCallback(reachabilityRef!, callback, &context) {
                stopNotifier()
                throw ReachabilityError.UnableToSetCallback
            }

            if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef!, reachabilitySerialQueue) {
                stopNotifier()
                throw ReachabilityError.UnableToSetDispatchQueue
            }

            // Perform an intial check
            dispatch_async(reachabilitySerialQueue) { () -> Void in
                let flags = self.reachabilityFlags
                self.reachabilityChanged(flags)
            }

            notifierRunning = true
        }

        public func stopNotifier() {
            defer { notifierRunning = false }
            guard let reachabilityRef = reachabilityRef else { return }

            SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
            SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
        }

        // MARK: - *** Connection test methods ***
        public func isReachable() -> Bool {
            let flags = reachabilityFlags
            return isReachableWithFlags(flags)
        }

        public func isReachableViaWWAN() -> Bool {

            let flags = reachabilityFlags

            // Check we're not on the simulator, we're REACHABLE and check we're on WWAN
            return isRunningOnDevice && isReachable(flags) && isOnWWAN(flags)
        }

        public func isReachableViaWiFi() -> Bool {

            let flags = reachabilityFlags

            // Check we're reachable
            if !isReachable(flags) {
                return false
            }

            // Must be on WiFi if reachable but not on an iOS device (i.e. simulator)
            if !isRunningOnDevice {
                return true
            }

            // Check we're NOT on WWAN
            return !isOnWWAN(flags)
        }

        // MARK: - *** Private methods ***
        private var isRunningOnDevice: Bool = {
            #if (arch(i386) || arch(x86_64)) && os(iOS)
                return false
            #else
                return true
            #endif
        }()

        private var notifierRunning = false
        private var reachabilityRef: SCNetworkReachability?
        private let reachabilitySerialQueue = dispatch_queue_create("uk.co.ashleymills.reachability", DISPATCH_QUEUE_SERIAL)

        private func reachabilityChanged(flags: SCNetworkReachabilityFlags) {

            guard previousFlags != flags else { return }

            if isReachableWithFlags(flags) {
                if let block = whenReachable {
                    block(self)
                }
            } else {
                if let block = whenUnreachable {
                    block(self)
                }
            }

            notificationCenter.postNotificationName(ReachabilityChangedNotification, object:self)

            previousFlags = flags
        }

        private func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {

            if !isReachable(flags) {
                return false
            }

            if isConnectionRequiredOrTransient(flags) {
                return false
            }

            if isRunningOnDevice {
                if isOnWWAN(flags) && !reachableOnWWAN {
                    // We don't want to connect when on 3G.
                    return false
                }
            }

            return true
        }

        // WWAN may be available, but not active until a connection has been established.
        // WiFi may require a connection for VPN on Demand.
        private func isConnectionRequired() -> Bool {
            return connectionRequired()
        }

        private func connectionRequired() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags)
        }

        // Dynamic, on demand connection?
        private func isConnectionOnDemand() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags) && isConnectionOnTrafficOrDemand(flags)
        }

        // Is user intervention required?
        private func isInterventionRequired() -> Bool {
            let flags = reachabilityFlags
            return isConnectionRequired(flags) && isInterventionRequired(flags)
        }

        private func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
            #if os(iOS)
                return flags.contains(.IsWWAN)
            #else
                return false
            #endif
        }
        private func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.Reachable)
        }
        private func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionRequired)
        }
        private func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.InterventionRequired)
        }
        private func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionOnTraffic)
        }
        private func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.ConnectionOnDemand)
        }
        func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
            return !flags.intersect([.ConnectionOnTraffic, .ConnectionOnDemand]).isEmpty
        }
        private func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.TransientConnection)
        }
        private func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.IsLocalAddress)
        }
        private func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
            return flags.contains(.IsDirect)
        }
        private func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
            let testcase:SCNetworkReachabilityFlags = [.ConnectionRequired, .TransientConnection]
            return flags.intersect(testcase) == testcase
        }

        private var reachabilityFlags: SCNetworkReachabilityFlags {

            guard let reachabilityRef = reachabilityRef else { return SCNetworkReachabilityFlags() }

            var flags = SCNetworkReachabilityFlags()
            let gotFlags = withUnsafeMutablePointer(&flags) {
                SCNetworkReachabilityGetFlags(reachabilityRef, UnsafeMutablePointer($0))
            }

            if gotFlags {
                return flags
            } else {
                return SCNetworkReachabilityFlags()
            }
        }

        override public var description: String {

            var W: String
            if isRunningOnDevice {
                W = isOnWWAN(reachabilityFlags) ? "W" : "-"
            } else {
                W = "X"
            }
            let R = isReachable(reachabilityFlags) ? "R" : "-"
            let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
            let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
            let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
            let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
            let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
            let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
            let d = isDirect(reachabilityFlags) ? "d" : "-"

            return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
        }

        deinit {
            stopNotifier()

            reachabilityRef = nil
            whenReachable = nil
            whenUnreachable = nil
        }
    }

Reachability class used from : https://github.com/ashleymills/Reachability.swift/blob/master/Reachability/Reachability.swift

Upvotes: 2

Anupam Mishra
Anupam Mishra

Reputation: 3588

Apply a periodic check by using NSTimer

override func viewDidLoad() {
    super.viewDidLoad()
    //Swift 2.2 selector syntax
    var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)

}

// must be internal or public. 
func update()
{
     if(!Reachability.isConnectedToNetwork()){
        print("Internet connection not available.");
        return
    }
}

your Reachability 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($0))
        }

        var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
            return false
        }

        let isReachable = flags == .Reachable
        let needsConnection = flags == .ConnectionRequired

        return isReachable && !needsConnection

    }
}

Upvotes: 1

Related Questions