Reachability vs NSURLSession response to detect internet connection - ios

I'm building out error cases for my API calls and would like to check for a condition when an internet connection in not available.
dataTaskWithRequest seems to handle this just fine and returns an NSError with code -1009 with a description of no internet connection. I doesn't have to wait for the request to time out.
In what instances would I want to use the Reachability Framework instead?
Thanks

I did a bit of research and found my answer in the Apple Docs.
The recommended best practice is to attempt the connection. If there is an issue with the connection, it gives you an NSError object that you should use to test for connectivity.
Apple recommends using Reachability only as a way to diagnose errors and further debug known issues. It seems like you should only use reachability to detect when the network comes back online after a failure.
"Always attempt to make a connection. Do not attempt to guess whether network service is available, and do not cache that determination.
If a connection fails, use the SCNetworkReachability API to help diagnose the cause of the failure."
source :
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/WhyNetworkingIsHard/WhyNetworkingIsHard.html#//apple_ref/doc/uid/TP40010220-CH13-SW3
"When any task completes, the NSURLSession object calls the delegate’s URLSession:task:didCompleteWithError: method with either an error object or nil (if the task completed successfully).
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."
source:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html

Related

What network protocol does Reachability use on iOS?

I am sure there is little % of iOS developers who haven't used Reachability, directly or via some framework like Alamofire.
What I am interested what it actually does? The best guess I can make is that given host it opens sockets and then listens for said host. But what network protocol does it use, is it simple UDP (it is not http as far as I can observe), where it periodically sends packages to said host and awaits answer?
Reachability sends no packets at all. It doesn't even tell you that a host is actually reachable. It just tells you that if you made a network request, then the system has an active network interface that it would try to use. That's all. There's no promise those packets would arrive (let alone that you'd get a response), just that iOS would try to send them.
Reachability really only has a couple of uses (and most of the time shouldn't be used). It is useful if "no network is available" would cause you to modify your user interface, or to tell you that it might be a good time to re-try a previously failed connection. (Since iOS 12, you should really use NWPathMonitor for this. I don't know any good uses for Reachability since iOS 12.)
The only way that you can know that a request will actually succeed is to try to send it and see if you get a response. That's why it is not recommended that you test Reachability before sending requests. Just send the request and deal with the errors if they come, since it is always possible to have an error, even if Reachability said you could connect.

is threre any configuration to control permission to internet in IOS

Is there any configuration like android user-permission in iOS to control access to internet?
I think all new projects access to internet by default, is that correct?
When I send a request to the internet it returns 0 http-error code, it means I can't access to the internet.
yes, it is correct all the new ios project have access to the internet by default.
A status code of 0 in an NSHTTPURLResponse object generally means there was no response and can occur for various reasons. The server will never return a status of 0 as this is not a valid HTTP status code.
Any http request will first be processed by the operating system, and during that phase you can get an error. Getting an error means that your request never got a response from the server (and with the exception of https requests where certificates were not accepted, most likely didn't reach the server).
If this phase succeeds, then you get eventually a reply from the server. This may take time, you may have to wait 60 seconds. Which is why you do all your internet requests on a background thread. That reply will have a status code (status, not error). The status code is NEVER 0.
By default, iOS doesn't allow http requests, and doesn't allow https requests to unsave servers, so you better use only https unless you have a very good reason. You will need a very good reason to convince Apple to let your app on the app store if you want http requests to succeed. But if you get this wrong, you get an error quite early on.
A status of zero most likely means that a background request didn't finish by the time you read the status, a basic programming mistake. You need to learn how background threads and callbacks work. Without that, you won't be able to use http successfully.
Also google for "Reachability" which can tell you if your app currently has internet access (like when WiFi and Mobile Data are turned off, or in Airplane mode).

HTTP request times out. Weak wifi or slow server?

I have a client/server application where the client is an iOS app and the server is a RESTful api. I have received complaints of requests timing out and I know that some/most of the time, this is due to poor wifi connectivity. In these situations I would like to display an error message on the client which indicates whether the request was received by the server.
Is it possible in iOS to tell the difference between a HTTP request that never reaches the intended destination and one that makes it all the way to the intended destination but never receives a response?
API Call only after you check whether your internet connectivity is reachable or not .show error message if not connected to internet(this is due to poor wifi connectivity)
Example : Check for internet connection availability in Swift
When its checked make api call handle error code 404(never reaches the intended destination) and 504(timeout error code never receives a response) and let user make it success only when status code is 200.But its good to handle 401(authorization error) also.
I don't know which library you are using that why can't provide any code example right now
Try Alamofire Library in swift I suggest handled error codes very well.

NSURLSession with background session configuration is not returning an error when there is no connection

When I set up NSURLSession/Alamofire.Manager with a background session configuration, if there is no internet connection, I'm expecting to receive the usual NSError "Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline.".
This happened regularly if I'm not using a background configuration, but if I do such configuration my callback/delegate method will never be called. It will eventually be called when I activate the wifi again.
I'd prefer to receive an error straight away. Am I missing something?
The reason that why the network failure in background session task does not return any error is:
In general an NSURLSession background session does not fail a task if
something goes wrong on the wire. Rather, it continues looking for a
good time to run the request and retries at that time. This continues
until the resource timeout expires (that is, the value in the
timeoutIntervalForResource property in the NSURLSessionConfiguration
object you use to create the session). The current default for that
value is one week!
I found the above answer at developer forum.
More details which might help in the background session:
Another benefit is that in a background session, we monitor the
network and power environment for you. This means that we cover things
like network reachability and connectivity for you, so you don't have
to use the reachability APIs at all. We won't attempt to establish a
connection until we know that the server is reachable. And similarly,
if the user is performing a download and steps out of Wi-Fi, normally
that task would then fail with a transmission error. But, in a
background session, we'll actually recover from that automatically and
retry it and resume where we left off if the download is resumable.
And you won't hear about that error.
Source: WWDC 2014
The API doesn't tell you that the network is not present, because that would be an error, indicating that the connection will never finish. In reality, it will, assuming the network eventually comes back.
If you need to receive the error for some reason, don't use a background session.
Alternatively, if you just want to know whether the network is up or not for some sort of UI hint, use the reachability API. With that said, don't refuse to start the request based on failed reachability, because reachability lies.

Should I listen for reachability updates in each UIViewController?

I see a lot of Reachability examples where people only display a message when reachability status changes.
But recently, I saw in Foursquare app that they display a message every time the user try to make an action requiring an Internet connection.
I think this is more robust and a better UX to remind the user he can't do anything without Internet. Mainly because users can switch between apps, do something else and forget he has no connection when he comes back.
Also as soon as they get the connection back I can see that they fetch data from the Internet and refresh the UI.
What I am really looking for is the best way to do this. How this is done?
Do they have a general UIViewController that checks for reachability each time it needs a connection?
Or do they have a kind of proxy class before each Internet request that cancels the request and display a message?
How you guys are dealing with that?
Thanks.
EDIT:
The solution I came up with is using AFNetworking which also provide reachability status in the box.
Basically I created an AFHTTPClient and set a reachability callback block on it to listen to status changes. The AFHTTPClient object is application wide (kind of a singleton). (in fact I have one AFHTTPClient per host I need to reach a.com, b.com ...).
Then when I need to perform a request I create a new AFHTTPRequestOperation (AFJSONRequestOperation in my case) and I enqueue it on my AFHTTPClient object.
In the failure block of the operation I check to see if the host is reachable with the networkReachabilityStatus property of the AFHTTPClient. If it's unreachable I display a message that there is no internet connection to the user.
I wrapped that up so I don't have to do this each time I create an operation. So now in the app, each time the user try to do something when there is no connection he got a message remembering him that he has no internet access.
I also use the reachability callback to reload data on a screen once I get the connection back (or rather once I am supposed to have a connection).
I don't know if it's best practice but I think it's nice to know that the app takes care of reloading important data as soon as a new connection is available.
If someone is interested by a sample code I can provide it.
On a WWDC talk this year the Apple engineer on stage recommended users to never base the application internet access on the Reachability example app status. Often reachability doesn't provide a complete information (it is based on a complex mechanism) and the suggestion provided by the engineer was this:
try to do your internet connection, whatever it is the Reachability status; then set your UI hint based on success/fail result
if it fails due to networking issue, then register to Reachability and retry again when Reachability gives the green light; this is needed when you want to recover automatically from the fail condition
in any case give the user the possibility to "force a retry", whatever is the Reachability status. If it succeeds, reset your UI hint immediately.
What the Apple engineer said is perfectly true: quite often you can see in the console log Reachability failure messages while the internet connection is perfectly alive.
Other thing: there is no better "network hint" than the one displayed in the status bar: if you have there the wi-fi icon, the 3G/4G icon, the cellular field strength.
Returning to your original question: there is no absolute better way to manage this stuff, this depends heavily on the application architecture. In case you prefer to concentrate your networking stuff in a dedicated class (not a UIViewController but a NSObject subclass) then it could make sense to define a read-only property for that class that is updated with "success/fail" after latest internet connection with the servers app (it makes no sense to ping other servers like Google or Apple: first of all it's not elegant, second the issue may come from your the servers that serve the app and not the device internet connection status!). #property (readonly) BOOL lastConnectionToMyServerSuccess
Then your view controllers can register (by KVO or by central notification) to this property changes and update their UI accordingly by showing an icon or else (I repeat: leave the user the possibility to try manually to connect to the internet). View controllers should unregister from KVO when out of sight ("viewWillDisappear:") or unloaded ("viewDidLoad:") or dealloc'd.
Of course this adds some extra complexities. E.g.: you use the app, the internet light was green. Then you suspend it, do something else and after a few minutes your return to the app. In such case the app should ping your servers to restore the internet light status again, as after a few minutes network conditions could have changed (e.g. you are on a train). In any case all loaded view controllers will get the KVO notification from the network dedicated class and update themselves.

Resources