Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When starting the app in airplane mode, the listener is not notified #2677

Closed
1 task done
alekop opened this issue Jan 4, 2019 · 8 comments
Closed
1 task done

When starting the app in airplane mode, the listener is not notified #2677

alekop opened this issue Jan 4, 2019 · 8 comments
Assignees
Milestone

Comments

@alekop
Copy link

alekop commented Jan 4, 2019

What did you do?

let reachability = ReachabilityNetworkManager(host: "www.apple.com")!
reachability.listener = { state in
    print("isReachable: \(state)")
}
reachability.startListening()

What did you expect to happen?

The print statement should have printed "isReachable: false"

What happened instead?

Nothing is printed when starting with no connectivity. But if you start the app with connectivity, it will print. The initial notification is not called in airplane mode.

The issue is that flags and previousFlags both have a rawValue of 0, so the guard in notifyListener returns. The previous flags should probably default unknown, rather than 0, which means not-reachable.

Alamofire Environment

Alamofire version: 4.8.0
Xcode version: 10.1
Swift version: 4.2
Platform(s) running Alamofire: iOS
macOS version running Xcode: 10.13.6

@cnoon
Copy link
Member

cnoon commented Jan 7, 2019

Hi @alekop,

Thank you for the report. Could you report which device and version of iOS you are running? Also, could you try the following code and see if it behaves better?

let reachability = ReachabilityNetworkManager()!
reachability.listener = { print("isReachable: \($0)") }
reachability.startListening()

I tend to use the non-host specific initializer as the host version tends to be less reliable.

If you could report back on your findings I'd greatly appreciate it.

@alekop
Copy link
Author

alekop commented Jan 7, 2019

Hi @cnoon,

I tried the no-hostname initializer, but it didn't make any difference. The issue seems to be here, in NetworkReachabilityManager.swift:

    listenerQueue.async {
        self.previousFlags = SCNetworkReachabilityFlags()
        self.notifyListener(self.flags ?? SCNetworkReachabilityFlags())
    }

Both previousFlags, and flags get initialized to the same value, which trips the guard in notifyListener:

    func notifyListener(_ flags: SCNetworkReachabilityFlags) {
        guard previousFlags != flags else { return }
        previousFlags = flags
        
        listener?(networkReachabilityStatusForFlags(flags))
    }

@cnoon
Copy link
Member

cnoon commented Jan 7, 2019

What versions of iOS have you tried this on @alekop? I'm guessing this is a change in functionality somewhere along the line.

@alekop
Copy link
Author

alekop commented Jan 7, 2019

I tried 11.4.1, 12, 12.1.

@cnoon
Copy link
Member

cnoon commented Jan 7, 2019

Cool. Thank you for all the info here!

My guess for now is that the behavior here changed somewhere along the lines under-the-hood because I'm positive this used to work on older versions. I'll do some investigation and get a fix put together. Just FYI, I'll be out on PTO for the rest of the week so I really doubt I'll be able to get a patch put together until I get back. If this is super pressing, I'd suggest making the fix you suggested and give it a whirl in a fork. If you're confident in the change, I'd also recommend putting together a PR.

The biggest thing we'll need to investigate with making that change is that it is compatible with older versions of iOS.

cnoon added a commit that referenced this issue Jan 14, 2019
Prior to this change, the reachability listener was notified at launch if the device was not in airplane mode. When in airplane mode, the reachability flags were 0, which is what we were defaulting the previous flags to. Because of this, the notifyListener function would early out since the flags had not changed.

The core issue here was that the default value of previousFlags was poorly chosen. It should instead default to a value that represents and unknown status. One way to do this would be to make previousFlags an optional. However, this change would not be backwards compatible, so it was abandoned.

The best backwards compatible way to make this change was to set previousFlags to a rawValue that is not currently used. That way, we can guarantee that the originally computed flags will be different than the default previous flags. This change results in the listener being called at launch even when in airplane mode.

Please refer to issue #2677 for more details.
@cnoon
Copy link
Member

cnoon commented Jan 15, 2019

Okay @alekop, I just pushed up #2688 to resolve the issue you are seeing. Your breakdown of the issue was spot on and I modified the original value of previousFlags accordingly. There's a bunch more detail in #2688 specifically.

I'm going to go ahead and close this issue out. Let's continue this conversation in #2688.

Cheers. 🍻

@cnoon cnoon closed this as completed Jan 15, 2019
@cnoon cnoon added this to the 4.8.1 milestone Jan 15, 2019
@agnosticdev
Copy link

My guess for now is that the behavior here changed somewhere along the lines under-the-hood because I'm positive this used to work on older versions.

I'm positive this used to work. Thank you for reporting this @alekop.
I need to do some regression testing on my own projects.

cnoon added a commit that referenced this issue Jan 15, 2019
Prior to this change, the reachability listener was notified at launch if the device was not in airplane mode. When in airplane mode, the reachability flags were 0, which is what we were defaulting the previous flags to. Because of this, the notifyListener function would early out since the flags had not changed.

The core issue here was that the default value of previousFlags was poorly chosen. It should instead default to a value that represents and unknown status. One way to do this would be to make previousFlags an optional. However, this change would not be backwards compatible, so it was abandoned.

The best backwards compatible way to make this change was to set previousFlags to a rawValue that is not currently used. That way, we can guarantee that the originally computed flags will be different than the default previous flags. This change results in the listener being called at launch even when in airplane mode.

Please refer to issue #2677 for more details.
@SparklingAir
Copy link

Hello! Problem is still here. I run my app from Xcode via wire on the device with turned on airplane mode and NetworkReachabilityManager()?.isReachable returns "reachable" merely once.

  • Alamofire 5.6.1
  • Xcode 13.2.1
  • Swift 5
  • iPhone 12
  • iOS 15.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants