IOS-1469 change to completion blocks IOS-1469
authorAlejandro Gelos <agp@pep.security>
Mon, 18 Feb 2019 12:37:17 +0100
branchIOS-1469
changeset 766485fcf2dcff11
parent 7648 457b8accabe7
child 7698 02e9e30e6202
IOS-1469 change to completion blocks
pEpForiOS/Util/Reachability/ReachabilityUtils.swift
pEpForiOS/Util/Reachability/ReachibilityUtilsProtocol.swift
pEpForiOSTests/TestUtils/ReachabilityUtilsTest/NetworkReachibilityMock.swift
pEpForiOSTests/TestUtils/ReachabilityUtilsTest/ReachabilityUtilsTests.swift
     1.1 --- a/pEpForiOS/Util/Reachability/ReachabilityUtils.swift	Thu Feb 14 18:51:34 2019 +0100
     1.2 +++ b/pEpForiOS/Util/Reachability/ReachabilityUtils.swift	Mon Feb 18 12:37:17 2019 +0100
     1.3 @@ -14,6 +14,7 @@
     1.4      ///
     1.5      /// - Parameter status: new internet connection state
     1.6      func didChangeReachibility(status: Reachability.Connection)
     1.7 +    func didFailToStartNotifier(error: Reachability.ReachabilityError)
     1.8  }
     1.9  
    1.10  /// # How to use:
    1.11 @@ -49,10 +50,7 @@
    1.12      
    1.13      var flags: SCNetworkReachabilityFlags? {
    1.14          didSet {
    1.15 -            let newState = getConnectionStatusFromFlags(fromFlags: flags)
    1.16 -            let oldState = getConnectionStatusFromFlags(fromFlags: oldValue)
    1.17 -            if newState != oldState, oldValue != nil { return }
    1.18 -            delegate?.didChangeReachibility(status: newState)
    1.19 +            callDelegateDidChangeReachibilityIfNeeded(newFlags: flags, oldFlags: oldValue)
    1.20          }
    1.21      }
    1.22      
    1.23 @@ -65,7 +63,7 @@
    1.24      }
    1.25      
    1.26      public convenience init?(hostname: String, queueQoS: DispatchQoS = .default,
    1.27 -                               targetQueue: DispatchQueue? = nil) {
    1.28 +                             targetQueue: DispatchQueue? = nil) {
    1.29          guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil }
    1.30          
    1.31          self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue)
    1.32 @@ -89,12 +87,31 @@
    1.33          stopNotifier()
    1.34      }
    1.35      
    1.36 -    public func getConnectionStatus() throws -> Connection {
    1.37 -        try setReachabilityFlags()
    1.38 -        return getConnectionStatusFromFlags(fromFlags: flags)
    1.39 +    public func getConnectionStatus(completion: @escaping ((Connection)->()),
    1.40 +                                       failure: @escaping ((ReachabilityError) -> ()) ) {
    1.41 +        setReachabilityFlags(
    1.42 +            completion: { [weak self] flags in
    1.43 +                guard let `self` = self else { return }
    1.44 +                let connectionStatud = self.getConnectionStatus(fromFlags: flags)
    1.45 +                completion(connectionStatud)},
    1.46 +            failure: { error in
    1.47 +                failure(error)
    1.48 +        })
    1.49      }
    1.50      
    1.51 -    public func startNotifier() throws {
    1.52 +    public func isLocal(completion: @escaping ((Bool)->()),
    1.53 +                           failure: @escaping ((ReachabilityError) -> ()) ) {
    1.54 +        setReachabilityFlags(
    1.55 +            completion: { [weak self] flags in
    1.56 +                guard let `self` = self else { return }
    1.57 +                let isLocal = self.isLocal(fromFlags: flags)
    1.58 +                completion(isLocal)},
    1.59 +            failure: { error in
    1.60 +              failure(error)
    1.61 +        })
    1.62 +    }
    1.63 +    
    1.64 +    public func startNotifier() {
    1.65          guard !notifierRunning else { return }
    1.66          
    1.67          let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in
    1.68 @@ -109,17 +126,22 @@
    1.69          context.info = UnsafeMutableRawPointer(Unmanaged<Reachability>.passUnretained(self).toOpaque())
    1.70          if !networkReachability.networkReachabilitySetCallback(reachabilityRef, callback, &context) {
    1.71              stopNotifier()
    1.72 -            throw ReachabilityError.failToGetReachabilityState
    1.73 +            delegate?.didFailToStartNotifier(error: .failToGetReachabilityState)
    1.74          }
    1.75          
    1.76          if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) {
    1.77              stopNotifier()
    1.78 -            throw ReachabilityError.failToGetReachabilityState
    1.79 +            delegate?.didFailToStartNotifier(error: .failToGetReachabilityState)
    1.80          }
    1.81          
    1.82          // Perform an initial check
    1.83 -        try setReachabilityFlags()
    1.84 -        
    1.85 +        setReachabilityFlags(
    1.86 +            completion: { [weak self] flags in
    1.87 +                self?.flags = flags },
    1.88 +            failure: { [weak self] error in
    1.89 +                self?.stopNotifier()
    1.90 +                self?.delegate?.didFailToStartNotifier(error: error)
    1.91 +        })
    1.92          notifierRunning = true
    1.93      }
    1.94      
    1.95 @@ -134,21 +156,39 @@
    1.96  
    1.97  // MARK: - Private methods
    1.98  private extension Reachability {
    1.99 -    private func setReachabilityFlags() throws {
   1.100 -        try reachabilitySerialQueue.sync { [weak self] in
   1.101 +    private func setReachabilityFlags(completion: @escaping ((SCNetworkReachabilityFlags)->()),
   1.102 +                                         failure: @escaping ((ReachabilityError) -> ()) ) {
   1.103 +        reachabilitySerialQueue.async { [weak self] in
   1.104              guard let `self` = self else { return }
   1.105              var flags = SCNetworkReachabilityFlags()
   1.106 -            guard networkReachability.networkReachabilityGetFlags(self.reachabilityRef, &flags) else {
   1.107 -                self.stopNotifier()
   1.108 -                throw ReachabilityError.failToGetReachabilityState
   1.109 +            guard self.networkReachability.networkReachabilityGetFlags(self.reachabilityRef, &flags) else {
   1.110 +                failure(.failToGetReachabilityState)
   1.111 +                return
   1.112              }
   1.113 -            
   1.114 -            self.flags = flags
   1.115 +             completion(flags)
   1.116          }
   1.117      }
   1.118      
   1.119 -    private func getConnectionStatusFromFlags(fromFlags flags: SCNetworkReachabilityFlags?) -> Connection {
   1.120 -        guard let flags = flags else { return .notConnected }
   1.121 -        return flags.contains(.reachable) ? .connected : .notConnected
   1.122 +    private func getConnectionStatus(fromFlags: SCNetworkReachabilityFlags) -> Connection {
   1.123 +        return fromFlags.contains(.reachable) ? .connected : .notConnected
   1.124 +    }
   1.125 +    
   1.126 +    private func isLocal(fromFlags: SCNetworkReachabilityFlags) -> Bool {
   1.127 +        return fromFlags.contains(.isLocalAddress)
   1.128 +    }
   1.129 +    
   1.130 +    private func callDelegateDidChangeReachibilityIfNeeded(newFlags: SCNetworkReachabilityFlags?,
   1.131 +                                                           oldFlags: SCNetworkReachabilityFlags?){
   1.132 +        guard let newFlags = newFlags else { return }
   1.133 +        let newState = getConnectionStatus(fromFlags: newFlags)
   1.134 +        
   1.135 +        guard let oldFlags = oldFlags else {
   1.136 +            delegate?.didChangeReachibility(status: newState)
   1.137 +            return
   1.138 +        }
   1.139 +        
   1.140 +        let oldState = getConnectionStatus(fromFlags: oldFlags)
   1.141 +        if newState == oldState { return }
   1.142 +        delegate?.didChangeReachibility(status: newState)
   1.143      }
   1.144  }
     2.1 --- a/pEpForiOS/Util/Reachability/ReachibilityUtilsProtocol.swift	Thu Feb 14 18:51:34 2019 +0100
     2.2 +++ b/pEpForiOS/Util/Reachability/ReachibilityUtilsProtocol.swift	Mon Feb 18 12:37:17 2019 +0100
     2.3 @@ -13,14 +13,22 @@
     2.4      
     2.5      /// Get current connection status
     2.6      ///
     2.7 -    /// - Returns: Connection enum with none for no internet connection otherwise connected
     2.8 -    /// - Throws: failToGetReachabilityState when failed to get current internet state
     2.9 -    func getConnectionStatus() throws -> Reachability.Connection
    2.10 +    /// - Parameters:
    2.11 +    ///   - completion: Connection enum with notConnected for no internet connection otherwise connected
    2.12 +    ///   - failure: failToGetReachabilityState when failed to get current internet flags state
    2.13 +    func getConnectionStatus(completion: @escaping ((Reachability.Connection)->()),
    2.14 +                                failure: @escaping ((Reachability.ReachabilityError) -> ()) )
    2.15      
    2.16 -    /// Start updateing internet conection state value.
    2.17 +    /// Check if current connection is local or not.
    2.18      ///
    2.19 -    /// - Throws: failToGetReachabilityState when failed to start notifying current state
    2.20 -    func startNotifier() throws
    2.21 +    /// - Parameters:
    2.22 +    ///   - completion: true is connection is local, false otherwise
    2.23 +    ///   - failure: failToGetReachabilityState when failed to get current internet flags state
    2.24 +    func isLocal(completion: @escaping ((Bool)->()),
    2.25 +                    failure: @escaping ((Reachability.ReachabilityError) -> ()) )
    2.26 +    
    2.27 +    /// /// Start updateing internet conection state value through ReachabilityDelegate
    2.28 +    func startNotifier()
    2.29      
    2.30      /// Stop updating internet connection value
    2.31      func stopNotifier()
     3.1 --- a/pEpForiOSTests/TestUtils/ReachabilityUtilsTest/NetworkReachibilityMock.swift	Thu Feb 14 18:51:34 2019 +0100
     3.2 +++ b/pEpForiOSTests/TestUtils/ReachabilityUtilsTest/NetworkReachibilityMock.swift	Mon Feb 18 12:37:17 2019 +0100
     3.3 @@ -40,7 +40,7 @@
     3.4      }
     3.5  }
     3.6  
     3.7 -class NoInternetNetworkReachibilityMock: NetworkReachabilityProtocol {
     3.8 +class NoInternetLocalNetworkReachibilityMock: NetworkReachabilityProtocol {
     3.9      let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in
    3.10          guard let info = info else { return }
    3.11          
    3.12 @@ -57,7 +57,7 @@
    3.13      func networkReachabilityGetFlags(_ target: SCNetworkReachability,
    3.14                                       _ flags: UnsafeMutablePointer<SCNetworkReachabilityFlags>)
    3.15          -> Bool {
    3.16 -        flags.pointee = []
    3.17 +        flags.pointee = [.isLocalAddress]
    3.18          return true
    3.19      }
    3.20      
     4.1 --- a/pEpForiOSTests/TestUtils/ReachabilityUtilsTest/ReachabilityUtilsTests.swift	Thu Feb 14 18:51:34 2019 +0100
     4.2 +++ b/pEpForiOSTests/TestUtils/ReachabilityUtilsTest/ReachabilityUtilsTests.swift	Mon Feb 18 12:37:17 2019 +0100
     4.3 @@ -14,11 +14,11 @@
     4.4      private var yesReachability: Reachability?
     4.5      private var noReachability:  Reachability?
     4.6      private let yesInternetNetworkReachibilityMock = YesInternetNetworkReachibilityMock()
     4.7 -    private let noInternetNetworkReachibilityMock  = NoInternetNetworkReachibilityMock()
     4.8 +    private let noInternetLocalNetworkReachibilityMock  = NoInternetLocalNetworkReachibilityMock()
     4.9      
    4.10      override func setUp() {
    4.11          yesReachability = Reachability(networkReachability: yesInternetNetworkReachibilityMock)
    4.12 -        noReachability  = Reachability(networkReachability: noInternetNetworkReachibilityMock)
    4.13 +        noReachability  = Reachability(networkReachability: noInternetLocalNetworkReachibilityMock)
    4.14      }
    4.15      
    4.16      override func tearDown() {
    4.17 @@ -27,53 +27,163 @@
    4.18          super.tearDown()
    4.19      }
    4.20      
    4.21 +    func testInit_ReachbilityRef_Hostname_QueueQoS_TargetQueue() {
    4.22 +        // Given
    4.23 +        let hostName = "www.google.com"
    4.24 +        guard let ref = yesInternetNetworkReachibilityMock.networkReachabilityCreateWithName(nil, hostName)
    4.25 +            else {
    4.26 +                XCTFail()
    4.27 +                return
    4.28 +        }
    4.29 +        let queueQoS = DispatchQoS.default
    4.30 +        let targetQueue: DispatchQueue? = nil
    4.31 +        
    4.32 +        // When
    4.33 +        let reachibility = Reachability(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue)
    4.34 +        
    4.35 +        //Then
    4.36 +        XCTAssertNotNil(reachibility)
    4.37 +    }
    4.38 +    
    4.39 +    func testInit_Hostname_QueueQoS_TargetQueue() {
    4.40 +        // Given
    4.41 +        let hostName = "www.google.com"
    4.42 +        let queueQoS = DispatchQoS.default
    4.43 +        let targetQueue: DispatchQueue? = nil
    4.44 +        
    4.45 +        // When
    4.46 +        let reachibility = Reachability(hostname: hostName, queueQoS: queueQoS, targetQueue: targetQueue)
    4.47 +        
    4.48 +        //Then
    4.49 +        XCTAssertNotNil(reachibility)
    4.50 +    }
    4.51 +    
    4.52 +    func testInit_QueueQoS_TargetQueue() {
    4.53 +        // Given
    4.54 +        let queueQoS = DispatchQoS.default
    4.55 +        let targetQueue: DispatchQueue? = nil
    4.56 +        
    4.57 +        // When
    4.58 +        let reachibility = Reachability(queueQoS: queueQoS, targetQueue: targetQueue)
    4.59 +        
    4.60 +        //Then
    4.61 +        XCTAssertNotNil(reachibility)
    4.62 +    }
    4.63 +    
    4.64 +    func testIsLocalNoInternet(){
    4.65 +        // Given
    4.66 +        guard let noReachability = noReachability else { XCTFail(); return }
    4.67 +        // When
    4.68 +        noReachability.isLocal(
    4.69 +        completion: { isLocal in
    4.70 +            // Then
    4.71 +            XCTAssertTrue(isLocal)
    4.72 +        },
    4.73 +        failure: { error in
    4.74 +            XCTFail()
    4.75 +        })
    4.76 +    }
    4.77 +    
    4.78 +    func testIsLocalYesInternet(){
    4.79 +        // Given
    4.80 +        guard let yesReachability = yesReachability else { XCTFail(); return }
    4.81 +        // When
    4.82 +        yesReachability.isLocal(
    4.83 +            completion: { isLocal in
    4.84 +                // Then
    4.85 +                XCTAssertFalse(isLocal)
    4.86 +        },
    4.87 +            failure: { error in
    4.88 +                XCTFail()
    4.89 +        })
    4.90 +    }
    4.91 +    
    4.92 +    func testIsLocalWithActualReachibilityLocalHost(){
    4.93 +        // Given
    4.94 +        guard let reachability = Reachability(hostname: "localhost") else { XCTFail(); return }
    4.95 +        // When
    4.96 +        reachability.isLocal(
    4.97 +            completion: { isLocal in
    4.98 +                // Then
    4.99 +                XCTAssertTrue(isLocal)
   4.100 +        },
   4.101 +            failure: { error in
   4.102 +                XCTFail()
   4.103 +        })
   4.104 +    }
   4.105 +    
   4.106 +    func testIsLocalWithActualReachibilityNoLocalHost(){
   4.107 +        // Given
   4.108 +        guard let reachability = Reachability(hostname: "google.com") else { XCTFail(); return }
   4.109 +        // When
   4.110 +        reachability.isLocal(
   4.111 +            completion: { isLocal in
   4.112 +                // Then
   4.113 +                XCTAssertFalse(isLocal)
   4.114 +        },
   4.115 +            failure: { error in
   4.116 +                XCTFail()
   4.117 +        })
   4.118 +    }
   4.119 +    
   4.120      func testGetConnectionStatusYesInternet() {
   4.121          // Given
   4.122 -        // Then
   4.123 -        guard let result = try? yesReachability?.getConnectionStatus() else{
   4.124 -            XCTFail("should not get nil in getConnectionStatus")
   4.125 -            return
   4.126 -        }
   4.127 -        // Then
   4.128 -        XCTAssertTrue(result == Reachability.Connection.connected)
   4.129 +        guard let yesReachability = yesReachability else { XCTFail(); return }
   4.130 +        
   4.131 +        // When
   4.132 +        yesReachability.getConnectionStatus(
   4.133 +            completion: { result in
   4.134 +                // Then
   4.135 +                XCTAssertTrue(result == Reachability.Connection.connected)
   4.136 +        },
   4.137 +            failure: { error in
   4.138 +                XCTFail()
   4.139 +        })
   4.140      }
   4.141      
   4.142      func testGetConnectionStatusNoInternet() {
   4.143 -        // Given
   4.144 +        guard let noReachability = noReachability else { XCTFail(); return }
   4.145 +        
   4.146          // When
   4.147 -        guard let result = try? noReachability?.getConnectionStatus() else{
   4.148 -            XCTFail("should not get nil in getConnectionStatus")
   4.149 -            return
   4.150 -        }
   4.151 -        // Then
   4.152 -        XCTAssertFalse(result == Reachability.Connection.connected)
   4.153 +        noReachability.getConnectionStatus(
   4.154 +            completion: { result in
   4.155 +                // Then
   4.156 +                XCTAssertFalse(result == Reachability.Connection.connected)
   4.157 +        },
   4.158 +            failure: { error in
   4.159 +                XCTFail()
   4.160 +        })
   4.161      }
   4.162      
   4.163      func testStartNotifierYesInternet(){
   4.164          // Given
   4.165 +        guard let yesReachability = yesReachability else { XCTFail(); return }
   4.166          let exp = expectation(description: "delegate called for connected")
   4.167          let expectedConnected = Reachability.Connection.connected
   4.168 -        
   4.169          let testDelegate = ReachibilityUtilsTestsDelegate(withExp: exp,
   4.170                                                            withExpectedConnected: expectedConnected)
   4.171 -        yesReachability?.delegate = testDelegate
   4.172 +        yesReachability.delegate = testDelegate
   4.173          
   4.174          // When
   4.175 -        try? yesReachability?.startNotifier()
   4.176 +        yesReachability.startNotifier()
   4.177 +        
   4.178 +        // Then
   4.179          waitForExpectations(timeout: TestUtil.waitTime)
   4.180      }
   4.181      
   4.182      func testStartNotifierNoInternet(){
   4.183          // Given
   4.184 -        let exp = expectation(description: "delegate called for not connected")
   4.185 +        guard let noReachability = noReachability else { XCTFail(); return }
   4.186 +        let exp = expectation(description: "delegate called for no connected")
   4.187          let expectedNotConnected = Reachability.Connection.notConnected
   4.188 -        
   4.189          let testDelegate = ReachibilityUtilsTestsDelegate(withExp: exp,
   4.190                                                            withExpectedConnected: expectedNotConnected)
   4.191 -        noReachability?.delegate = testDelegate
   4.192 +        noReachability.delegate = testDelegate
   4.193          
   4.194          // When
   4.195 -        try? noReachability?.startNotifier()
   4.196 +        noReachability.startNotifier()
   4.197 +        
   4.198 +        // Then
   4.199          waitForExpectations(timeout: TestUtil.waitTime)
   4.200      }
   4.201  }
   4.202 @@ -91,6 +201,11 @@
   4.203  
   4.204  // MARK: - ReachabilityDelegate
   4.205  extension ReachibilityUtilsTestsDelegate: ReachabilityDelegate{
   4.206 +    func didFailToStartNotifier(error: Reachability.ReachabilityError) {
   4.207 +        XCTFail()
   4.208 +        exp.fulfill()
   4.209 +    }
   4.210 +    
   4.211      func didChangeReachibility(status: Reachability.Connection) {
   4.212          // Then
   4.213          XCTAssertEqual(status, expedConnected)