askaale
askaale

Reputation: 1199

URLSession dataTask timeout error

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!

Upvotes: 8

Views: 16049

Answers (2)

Fattie
Fattie

Reputation: 12621

The actual answer is very simple ...

if let urlError = error as? URLError {
    print("url error", urlError)
    if urlError.code == .timedOut {
        print("Did find a timedOut ...")
    }
}

Don't forget to "print everything out" during development to see what's going on

    print("d", data)
    print("r", response)
    print("e", error)

enter image description here

Look at the autocomplete ...

When you are typing the "== .timedOut" code above you will see the innumerable possible codes,

enter image description here

Set your timeout to say 3 seconds ...

var request = URLRequest(typical: "\(___base)/blah ...")
request.httpBody = try? JSONSerialization.data(withJSONObject: blah ...)
request.timeoutInterval = 3.0
URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) i

Certainly since the 2020s, you would rarely have a timeout longer than say three or four seconds (particularly for anything secure like say login).

Upvotes: 0

dgatwood
dgatwood

Reputation: 10407

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.

Upvotes: 3

Related Questions