Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting DNS failure with NSURLSession background config?

Is it possible to detect DNS lookup failures when using NSURLSession with a background configuration ?

If I use a default config and a completion handler, DNS resolution failure is reported in the error parameter. If I use a background configuration however, the failure is never reported and the delegate methods never called.

The Apple documentation for the NSURLSessionTaskDelegate Protocol says :

Server errors are not reported through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host.

Which suggests that I should be seeing the DNS failure message there. Code below illustrates the behaviour. I have tested on iOS 8.4, and 9 on both device and simulator and searched the dev forums, SO and using popular search engines but come up empty. I'm sure I must be missing something really simple.

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, NSURLSessionTaskDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


        let bgsesh = NSURLSession(configuration: NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("foobarbazqwux"), delegate: self, delegateQueue: nil)
        let dfsesh = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: nil, delegateQueue: nil)

        let url = NSURL(string: "http://foobarbaz.qwzx")!
        let a = dfsesh.downloadTaskWithURL(url) { (url:NSURL?, resp:NSURLResponse?, err:NSError?) -> Void in
            print(err)

            /* 
            Optional(Error Domain=NSURLErrorDomain Code=-1003
            "A server with the specified hostname could not be found." 
            UserInfo=0x146e8050 {
                NSErrorFailingURLStringKey=http://foobarbaz.qwzx/,
                _kCFStreamErrorCodeKey=8,
                NSErrorFailingURLKey=http://foobarbaz.qwzx/, 
                NSLocalizedDescription=A server with the specified hostname could not be found., 
                _kCFStreamErrorDomainKey=12, 
                NSUnderlyingError=0x14693ab0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1003.)"
            })
            */
        }
        a.resume()

        let b = bgsesh.downloadTaskWithURL(url)
        b.resume()

        return true
    }
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        // never runs, DNS failure is not reported for background config :-(
        print("didCompleteWithError: \(task.taskIdentifier) \(error)")
    }
    // ... other delegate methods ...
}
like image 287
Steve Trewick Avatar asked Jul 07 '15 22:07

Steve Trewick


1 Answers

Set URLSessionConfiguration.timeoutIntervalForResource.

The resource timeout interval controls how long (in seconds) to wait for an entire resource to transfer before giving up.

The default value is 7 days.

For example,

let conf = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("foobarbazqwux")
conf.timeoutIntervalForResource = 60    // seconds

let session = NSURLSession(configuration: conf, delegate: self, delegateQueue: nil)

In this case, the system will retry to connect and calls the delegate if it's still failling after 60 seconds.

EDIT following the comment of @algrid:

This value should take into account the transfer time of the resource. It therefore depends on the resource size to download/upload and the network speed.

like image 125
Gawen Avatar answered Oct 26 '22 10:10

Gawen