0

When I turn off my WiFi connection and run the following code on the iPhone 6s 10.2 simulator, the callback is never executed. I expected the callback to fire fairly quickly with an error like "No Internet connection".

NSLog(@"request-start");
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.google.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:0];
task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    NSLog(@"request-end");
}];
[task resume];

My Problem

I'm fetching data when the app first loads. If wifi is turned off, I need to show an error. If I set a timeout, it is obeyed - but it would need to be 10+ seconds and I'd rather not make them wait. I've also tried to detect the network status with reachability, but the network status is often unknown when the app is first loaded.

bendytree
  • 13,095
  • 11
  • 75
  • 91
  • Could this be because of your use of the shared session? – matt Feb 20 '17 at 19:48
  • "but it would need to be 10+ seconds and I'd rather not make them wait". I don't understand, if your connection takes 10 seconds to receive a response, why don't you set a timeout? You need to have a timeout set to handle the connection errors and timeouts. Even if "wifi is on" doesnt mean the connection will work 100%. You should not focus on "making people wait" , but instead handle the errors and the User Interface accordingly to maybe show a progress infobar to your user when the connection takes more time than expected. –  Feb 20 '17 at 19:51
  • @matt - I'm not sure - I tried `defaultSessionConfiguration` and `ephemeralSessionConfiguration` and got the same results – bendytree Feb 20 '17 at 20:13
  • @Sneak - I do have a timeout in my real project and I don't mind making them wait if there's a slow connection. But if there's no wifi, then I'd rather not make them wait the full timeout - like ajax/browsers/curl/etc – bendytree Feb 20 '17 at 20:23

1 Answers1

2

timeoutIntervalForResource

This property determines the resource timeout interval for all tasks within sessions based on this configuration. The resource timeout interval controls how long (in seconds) to wait for an entire resource to transfer before giving up. The resource timer starts when the request is initiated and counts until either the request completes or this timeout interval is reached, whichever comes first.

The default value is 7 days.

and

timeoutIntervalForRequest

Important

Any upload or download tasks created by a background session are automatically retried if the original request fails due to a timeout. To configure how long an upload or download task should be allowed to be retried or transferred, use the timeoutIntervalForResource property.

The default value is 60.

So, without your timeout set, your connection will run for 7 days.

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!

Source

Community
  • 1
  • 1
  • Thanks @Sneak. I didn't realize it was intentionally designed to "wait for a good time to retry the request". Are there ways to make a request without waiting for a good time to retry? – bendytree Feb 20 '17 at 20:32
  • @bendytree Your only option is this: http://stackoverflow.com/questions/7938650/ios-detect-3g-or-wifi/7938778#7938778 , however, the best practices and guideline for Apple is to check for reachability **AFTER** you encounter a connection error, to show the appropriate message, not on every request you make. However, I don't know what your use-case is, that is all you need my friend. GL , BTW, you should set the timeout no matter what to avoid running into wierd stuff. –  Feb 20 '17 at 20:35
  • Thanks for your help. Basically I don't want the user to wait the full timeout (even just 10 seconds) when there's obviously not a connection. I guess that's just not possible on iOS. – bendytree Feb 20 '17 at 20:42
  • @bendytree For a single request here and there, it shouldnt be any problems using the above linked solution. However, If you are handling many requests etc. there is no straightforward way to eliminate the need of timout errors. However, there is an observer to the reachability that you can add to detect changes, check this: http://stackoverflow.com/questions/20919244/kreachabilitychangednotification-is-called-multiple-times , but remember nothing is 100% guaranteed. You can try it out tho. –  Feb 20 '17 at 20:48