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.
askaale
Updated on June 07, 2022Comments
-
askaale almost 2 years
I am currently experiencing some issues regarding the URLSession, while trying to post data to my web server. This however, works perfectly. What seems to not work, is the timeout I have set. This is rather crucial for my whole app, as I don't want the users to be 'loading' forever, without any type of error message. Here is my code:
var request = URLRequest(url: URL(string: "https://www.mywebsite.com/file.php")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 20) let urlconfig = URLSessionConfiguration.default urlconfig.timeoutIntervalForRequest = 20 urlconfig.timeoutIntervalForResource = 20 request.httpMethod = "POST" let session = URLSession(configuration: urlconfig, delegate: self, delegateQueue: nil)//URLSession.shared let body = "receiver=\(receiverID)" request.httpBody = body.data(using: String.Encoding.utf8, allowLossyConversion: true) request.timeoutInterval = 20 session.dataTask(with: request) {data, response, err in if err == nil { do { let jsonResult:NSDictionary? = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary let jsonComp = jsonResult?.value(forKey: "completion") as! String if jsonComp == "done" { } else { } }catch{} } else { } }.resume()
I simply want to set the timeout to 20 seconds, and then return an error (an alert). How can I do this? I feel that I have tried everything possible, just by configuration the
URLSessionConfiguration
, and set the.timeoutInterval
.Help would be greatly appreciated!
-
askaale over 7 yearsOkay, thanks for sorting this out. I get it! However, are you telling me that after x amount time, the request will eventually fail? So if I create an alert in 'if error == nil { } else { print("something here") }', the console will print 'Something here'? And also, could I potentially just cancel the request after x amount of seconds, through my timer?
-
dgatwood over 7 yearsEventually, it might fail, in which case yes, you'd get called with a non-nil error. I think the default is to give up 90 seconds without receiving a single byte of data, but I might be remembering the number wrong. The default is to not have a maximum total time at all, because that would cause longer downloads to fail.
-
dgatwood over 7 yearsYou could eventually cancel the request, but you probably shouldn't. The general recommendation from Apple is to let the user cancel the request if the user no longer cares about the data. Otherwise, assume that the user eventually wants to get the data, even if it takes a long time.
-
askaale over 7 yearsI see. I am actually doing a transaction through Stripe. So I think I'll stick with a 70 seconds timeout, in case some people are afraid of something happening to their money.