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

Docs on Reachability contradict Apple's docs. #2701

Closed
ileitch opened this Issue May 6, 2015 · 21 comments

Comments

Projects
None yet
6 participants
@ileitch
Copy link

ileitch commented May 6, 2015

In the AFNetworking docs about Reachability:

"Network reachability is a diagnostic tool that can be used to understand why a request might have failed. It should not be used to determine whether or not to make a request."

Apple's docs:

"If the task failed, most apps should retry the request until either the user cancels the download or the server returns an error indicating that the request will never succeed. Your app should not retry immediately, however. Instead, it should use reachability APIs to determine whether the server is reachable, and should make a new request only when it receives a notification that reachability has changed."

Why does AFNetworking recommend against using reachability to determine if it's appropriate to make a request?

@kcharwood

This comment has been minimized.

Copy link
Contributor

kcharwood commented May 6, 2015

My personal experience with Reachability is that I've needed to use it to determine when I definitely should not send a request to server. Getting a status of reachable does not guarantee the request I am about to send will actually make it to the destined server, so I should not write code that assumes that. When I get NotReachable, I can be sure ahead of time that it won't make it.

@taylesworth

This comment has been minimized.

Copy link

taylesworth commented May 6, 2015

I think the difference is that Apple is talking about how to handle a potential retry after a request has failed. You should never use Reachability to decide whether or not to send the original request. It can be used for diagnostics to determine how to handle failures, for example, whether or not to retry the request immediately.

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 6, 2015

Watch any of Apple's sessions; Reachability's docs are incorrect. You must not use Reachability to gate connection attempts.

Edit: Actually, on reflection, they're both correct as written. There's no contradiction here.

Or heck, look at Apple's apps. Safari's a great example. Safari uses Reachability to determine when a network connection comes online. When it does, it automatically reloads a page it wasn't able to load. But the reload button is always available, even when iOS thinks you're offline. The reason is simple: Pushing that button might work. The user may know better than the Reachability.

Try 2012 session 706, "Networking Best Practices."

The whole video is great, but you should watch from 32:50. The statement at 32:56 is very clear: "Don't check the Reachability object to determine if something's available. It can be deceptive in some cases. You want to go ahead and just make the attempt anyhow. If you succeed, you're done. If you don't succeed, you want to wait for another Reachability change notification before you attempt again."

Though this is misleading, too: If your UI allows you to add a simple way for the user to indicate they want to try again now, like Safari has, you should definitely try again if they tap that rather than just waiting. iOS can be lazy about connections; until something (maybe you, maybe something in the background) tries networking, it won't try. It may take a while before the OS tries to connect some background process, realizes it's connected, and lets you know that.

This is what Apple's talking about in their docs: Your app should not continuously retry after failure. If it fails, wait for user interaction or a Reachability notification. But never stop the user from manually retrying, and never gate the initial attempt.

Sorry if I'm going on about this, but I'm pretty passionate about this because I've seen it done wrong so many times. Networking is unreliable in practice, and you need to adapt well to that.

@kcharwood: That's the wrong behaviour. If you're told the server is unreachable, it only means that it's not currently reachable. Attempting a connection may make it reachable.

@taylesworth has it right. :)

@kcharwood

This comment has been minimized.

Copy link
Contributor

kcharwood commented May 6, 2015

@tewha I think we're saying the same thing, but I am not sure. If I see notreachable, I am not going to send out the request. In addition, when I do see reachable, I can't assume it will actually make it. I need to be prepared for that to still timeout, fail, etc and code for that. Make sense?

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

@kcharwood I understood you. We're not saying the same thing.

If Reachability says the server is unreachable, you're supposed to try anyway. Because even though Reachability says it won't work, it will often be wrong about that and it will work.

This is how unreliable networking is: Even the indication that it's not available might be wrong. :)

@kcharwood

This comment has been minimized.

Copy link
Contributor

kcharwood commented May 7, 2015

@tewha That's really interesting. Certainly doesnt match my experience with Reachability. In just about all cases I can remember, trying the request anyway leads to a request that eventually times out, giving a poor user experience.

Have you seen requests work often when reachability declares something as not reachable? Just doesnt seem to match up with the 100+ apps I've been involved with.

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

Yup. Happens all the time with Safari on my iPad.

@taylesworth

This comment has been minimized.

Copy link

taylesworth commented May 7, 2015

@kcharwood In most cases, you are correct that Reachability is very reliable. However it can and does get confused under some conditions and reports the network as unavailable when it is. I know this first-hand because we unfortunately implemented our mobile app to disable most features when Reachability reported the network as unavailable. We then discovered the edge cases which caused users to be unable to access features even though they clearly had network coverage.

One of the easiest ways for us to reproduce this was to use the app on an iPhone on WiFi, enter an elevator on a high floor in an office building, put the phone in a pocket while going down to the first floor, exit the building, and then open the app. Around 5% of the time, doing this will not trigger a Reachability notification when the phone connected to the cellular network. It will continue to report network unavailable from losing it during the elevator ride.

That's when I researched more and discovered that Apple recommends against using Reachability to prevent network requests. I also looked at other apps -- Safari, Facebook, Twitter, Google+. None of them prevent users from doing whatever they want when they show a no-network-connected banner. They use Reachability merely to show the banner so users know that they may not be able to use the app. But they still send requests based on user interaction even if they believe they don't have connectivity.

@ileitch

This comment has been minimized.

Copy link
Author

ileitch commented May 7, 2015

Wow, quite a lot of confusion here. My takeaways:

  • Do not use Reachability to determine if an original request should be sent.
  • (optionally) Use Reachability to determine if a request should be automatically retried.
  • Reachability is most useful for giving the user ahead of time feedback about connectivity status (e.g a banner). Potentially lessening the annoyance they feel when a request fails.
@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

Reachability is not "confused." Reachability is doing exactly what it's supposed to do. This is what's so important to understand about Reachability, and it's obvious if you think about the power level involved in networking:

  • Reachability will report that unreachable if the networking hardware is powered down.
  • Attempting to make a connection will power up the networking hardware.

If you are relying on Reachability saying something might be reachable, you are relying on something else (a background process) powering up the networking hardware. There's a number of them in the OS, don't get me wrong, so it's unlikely it'll stay down forever. (Seems to be more of them every iOS release!) But many of these processes can be disabled.

The phone can be sitting in the middle of a room with beautiful networking. Reachability will report "not reachable." But if you were to try sending a network request, the hardware would obediently power up, establish a connection, and the request would succeed.

@ileitch I'd add the word "automatically" to your second point before "retried." Otherwise, that's great advice. :)

@ileitch

This comment has been minimized.

Copy link
Author

ileitch commented May 7, 2015

Yes, automatic transparent retry is indeed what I meant :)

@taylesworth

This comment has been minimized.

Copy link

taylesworth commented May 7, 2015

@tewha Fair enough. However in my experience Reachability can continue to report "not reachable" even when other apps have just used the networking hardware. That was the situation we ran into. Switching to Safari, making a successful web page request, and returning to our app would still claim that our server was unreachable.

@ileitch Yes, your takeaways are spot-on.

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

@taylesworth That could be, too. Networking is a mess. :) I wonder if tearing down the Reachability and re-establishing it would have fixed it.

@taylesworth

This comment has been minimized.

Copy link

taylesworth commented May 7, 2015

@tewha Probably. Now if only we could have something to indicate when we should re-establish Reachability... ;-)

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

Oh, I thought of one other thing. @kcharwood, this might explain the differences we see. If your app is set to require a persistent WiFi connection, the iOS is likely more aggressive about getting networking back on. I still wouldn't completely trust this, though, as it's probably not as aggressive enough to detect a network connection faster than the user can tap a retry button.

@ileitch's takeaway is still the right approach.

@kcharwood

This comment has been minimized.

Copy link
Contributor

kcharwood commented May 7, 2015

We actually do set that in quite a few of our apps, so that may be a good note worth calling out.

@fcy

This comment has been minimized.

Copy link

fcy commented May 7, 2015

@ileitch what about a PR to add your takeaways points to AFNetworking docs? (I'm assuming it is possible to open a PR for the docs)

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

In any case, I think we can update the docs. Where are they? :)

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

Nevermind, found them, I'll fix something up and y'all can see if it needs more work.

@tewha

This comment has been minimized.

Copy link
Contributor

tewha commented May 7, 2015

There. I think this definitely needs more work before its merged, and I'll look at it again, but if you guys have any feedback:

https://github.com/AFNetworking/AFNetworking/pull/2704/files

@mattt

This comment has been minimized.

Copy link
Contributor

mattt commented May 11, 2015

To address the original issue:

@ileitch The two statements you cited are actually not incompatible. As @taylesworth pointed out, Apple's documentation here is talking about using reachability as a condition for retry, whereas AFNetworking's documentation is making a broader statement that reachability should not be used as a condition for initial request (which is @tewha's point). AFNetworking's not incorrect, per se, it could certainly be improved. AFNetworkReachabilityManager is one of the more misunderstood components of AFNetworking, and something I've been wanting to address for a while.

Thank you all for your discussion so far. I would encourage you to lend any further insights into #2704, so that we can make those necessary improvements to the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.