NSURLSession: How to increase time out for URL requests?
ObjC
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 30.0;
sessionConfig.timeoutIntervalForResource = 60.0;
Swift
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 30.0
sessionConfig.timeoutIntervalForResource = 60.0
let session = URLSession(configuration: sessionConfig)
What docs say
timeoutIntervalForRequest
and timeoutIntervalForResource
specify the timeout interval for the request as well as the resource.
timeoutIntervalForRequest
- The timeout interval to use when waiting
for additional data. The timer associated with this value is reset
whenever new data arrives. When the request timer reaches the
specified interval without receiving any new data, it triggers a
timeout.
timeoutIntervalForResource
- The maximum amount of time that a
resource request should be allowed to take. This value controls how
long 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.
Based on NSURLSessionConfiguration Class Reference
Request Timeout NSURLSession
You can't modify your request because for some reason you went with immutable option. Since NSMutableURLRequest is a subclass of NSURLRequest you can use the very same initializer init(URL:cachePolicy:timeoutInterval:)
to create an mutable instance and set default timeout. And then configure (mutate) this request as you need.
let request = NSMutableURLRequest(URL: url!, cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 5.0)
NSURLSession sharedSession default timeout
There are two timeouts for URL sessions. The first is the maximum time allowed between receiving new data. This is called the timeoutIntervalForRequest
. The second is the maximum time the entire request is allowed to take (assuming it's regularly receiving new data). This is called the timeoutIntervalForResource
.
Both of these timeouts are configured by default using NSURLSessionConfiguration
, and can be overridden on the NSURLRequest
.
The default timeoutIntervalForRequest
is 60 seconds.
The default timeoutIntervalForResource
is 7 days.
NSURLSession set request timeout accurately
It can be used, but it rarely makes sense to do so.
The expected user experience from an iOS app is that when the user asks to download or view some web-based resource, the fetch should continue, retrying/resuming as needed, until the user explicitly cancels it.
That said, if you're talking about fetching something that isn't requested by the user, or if you are fetching additional optional data that you can live without, adding a resource timeout is probably fine. I'm not sure why you would bother to cancel it, though. After all, if you've already spent the network bandwidth to download half of the data, it probably makes sense to let it finish, or else that time is wasted.
Instead, it is usually better to time out any UI that is blocked by the fetch, if applicable, but continue fetching the request and cache it. That way, the next time the user does something that would cause a similar fetch to occur, you already have the data.
The only exception I can think of would be fetching video fragments or something similar, where if it takes too long, you need to abort the transfer and switch to a different, lower-quality stream. But in most apps, that should be handled by the HLS support in iOS itself, so you don't have to manage that.
NSURLSession timeout
You cannot change the timeout on the sharedSession
or a sessions configuration
property. You have to set the timeout when the session is created. See this for an example of how to create a session and its timeout: https://stackoverflow.com/a/30427187/78496
Handle URLSession timeout
You can cast your error to URLError
type and then use the code
property to safely check if it's a session timeout error:
if (err as? URLError)?.code == .timedOut {
// Handle session timeout
}
Can't catch Time out error using URLSession
Printing the rawValue
s of all the possible URLError
codes:
unknown: -1
cancelled: -999
badURL: -1000
timedOut: -1001
unsupportedURL: -1002
cannotFindHost: -1003
cannotConnectToHost: -1004
networkConnectionLost: -1005
dnsLookupFailed: -1006
httpTooManyRedirects: -1007
resourceUnavailable: -1008
notConnectedToInternet: -1009
redirectToNonExistentLocation: -1010
badServerResponse: -1011
userCancelledAuthentication: -1012
userAuthenticationRequired: -1013
zeroByteResource: -1014
cannotDecodeRawData: -1015
cannotDecodeContentData: -1016
cannotParseResponse: -1017
appTransportSecurityRequiresSecureConnection: -1022
fileDoesNotExist: -1100
fileIsDirectory: -1101
noPermissionsToReadFile: -1102
dataLengthExceedsMaximum: -1103
secureConnectionFailed: -1200
serverCertificateHasBadDate: -1201
serverCertificateUntrusted: -1202
serverCertificateHasUnknownRoot: -1203
serverCertificateNotYetValid: -1204
clientCertificateRejected: -1205
clientCertificateRequired: -1206
cannotLoadFromNetwork: -2000
cannotCreateFile: -3000
cannotOpenFile: -3001
cannotCloseFile: -3002
cannotWriteToFile: -3003
cannotRemoveFile: -3004
cannotMoveFile: -3005
downloadDecodingFailedMidStream: -3006
downloadDecodingFailedToComplete: -3007
internationalRoamingOff: -1018
callIsActive: -1019
dataNotAllowed: -1020
requestBodyStreamExhausted: -1021
backgroundSessionRequiresSharedContainer: -995
backgroundSessionInUseByAnotherProcess: -996
backgroundSessionWasDisconnected: -997
You can see that you are looking for notConnectedToInternet
code. (the one with rawValue -1009)
So, your code might look like this:
switch (err as? URLError)?.code {
case .some(.timedOut):
// Handle session timeout
case .some(.notConnectedToInternet):
// Handle not connected to internet
default: break
}
URLSession dataTask timeout error
Timeouts should always several minutes long, not twenty seconds. It can take twenty or thirty seconds just to do a DNS lookup on a bad cellular connection, and using a twenty-second timeout means that on a poor network, your app will be completely unusable.
The way you handle this in the UI should be entirely independent of the networking code. Start the request and simultaneously create and start a timer. If your session delegate hasn't gotten a ...didReceiveResponse:...
call by the time the timer fires, show a "slow network" UI, but let the network request continue until it fails.
Additionally, if your requests are idempotent (that is, if issuing the request twice is safe), you might consider having a second timer with a very short interval (say 5 seconds), and if you haven't gotten a didReceiveResponse:
call within that time, start a second request in parallel. If that second task doesn't get a response by the time your twenty-second timer fires, cancel it. If it gets a response first, cancel the original request. This can help reduce the impact of packet loss on user-perceived latency.
NSURLSessionDataTask timeout subsequent requests failing
I didnt see you resume the task you started. You need to declare:
[task resume];
This line Resumes the task, if it is suspended.
Try to call the NSURLSession as follows:
[NSURLSession sharedSessison] instead of self.session
and invalidate the session by:
[[NSURLSession sharedSession]invalidateAndCancel];
From Apple's Documentation:
When your app no longer needs a session, invalidate it by calling either invalidateAndCancel (to cancel outstanding tasks) or finishTasksAndInvalidate (to allow outstanding tasks to finish before invalidating the object).
- (void)invalidateAndCancel
Once invalidated, references to the delegate and callback objects are
broken. Session objects cannot be reused.
To allow outstanding tasks to run until completion, call finishTasksAndInvalidate instead.
- (void)finishTasksAndInvalidate
This method returns immediately without waiting for tasks to finish. Once a session is invalidated, new tasks cannot be created in the session, but existing tasks continue until completion. After the last task finishes and the session makes the last delegate call, references to the delegate and callback objects are broken. Session objects cannot be reused.
To cancel all outstanding tasks, call invalidateAndCancel instead.
Related Topics
In iOS, How to Store a Secret "Key" That Will Allow Me to Communicate with My Server
How to Use Any in Codable Type
How to Get Audio Volume Level, and Volume Changed Notifications on iOS
Using Iskindofclass with Swift
How to Achieve a "Clock Wipe"/ Radial Wipe Effect in iOS
Combine Framework: How to Process Each Element of Array Asynchronously Before Proceeding
How to Use Avcapturephotooutput
Disable Uipageviewcontroller Bounce
How to Rotate Text for Uibutton and Uilabel in Swift
Remove Gradient Background from Uiwebview
iOS 7 -- Navigationcontroller Is Setting the Contentinset and Contentoffset of My Uiscrollview
How to Detect When Keyboard Is Shown and Hidden
iPhone Sdk Cgaffinetransform Getting the Angle of Rotation of an Object
Linker Command Failed with Exit Code 1 (Use -V to See Invocation), Xcode 8, Swift 3
Invalid Swift Support/Invalid Implementation of Swift
How to Trap on Uiviewalertforunsatisfiableconstraints