3

I'm trying to write default behaviour for a delegate method using a Swift extension as below, but it is never called. Does anyone know why or how to do it the right way?

extension NSURLSessionDelegate {

    public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        //default behaviour here
    }
}

Adding override does not work either.

According to this, Apple's default implementation looks like:

extension NSURLSessionDelegate {
    func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) { }
    func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { }
}

My DataTask calls typically look like this:

let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
    sessionConfiguration.HTTPCookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
let session = NSURLSession(configuration: sessionConfiguration)
let requestURL = NSURL(string:"https:www.google.com/blabla")

session.dataTaskWithURL(requestURL!, completionHandler: completion).resume()

Where completion will typically be a Swift closure received via parameter.

I need to implement the URLSession(... didReceiveChallenge ...) function for all nsurlsessiontask implementations throughout my app, but can't set my session's delegate as I need to use the completionHandler (as mentioned in my comment below).

Stephan
  • 881
  • 9
  • 24
  • 1
    If you implements your method in your delegate, is the method ever called ? Maybe the delegate methods are not called either way. Otherwise your implementation looks fine. – Michaël Azevedo Mar 04 '16 at 10:08
  • I'm using `dataTaskWithURL` with a completionHandler (which I can't change to manage via delegate for other reasons), so I can't set a specific delegate for my `NSURLSession` when creating the session - else the completionHandler isn't called. See also my updated question. – Stephan Mar 04 '16 at 11:22

1 Answers1

2

You can extends the NSURLSessionDelegate protocol for adding default implementation, but your NSURLSession objects needs a delegate.

This delegate can only be set using +sessionWithConfiguration:delegate:delegateQueue: (since the delegate property is read only), so your only way to set it is to subclass NSURLSession, override +sessionWithConfiguration: and call the initializer with the delegate property. The issue here is that you have to replace all your NSURLSession objects to MyCustomSessionClass. objects.

I suggest you to create a SessionCreator class which will conforms to NSURLSessionDelegate protocol and will create NSURLSessionobjects. You still have to replace the creation of your objects, but at least the object isn't the delegate of itself.

public class SessionCreator:NSObject,NSURLSessionDelegate {

    //MARK: - Singleton method    
    class var sharedInstance :SessionCreator {
        struct Singleton {
            static let instance = SessionCreator()
        }
        return Singleton.instance
    }

    //MARK: - Public class method    
    public class func createSessionWithConfiguration (configuration:NSURLSessionConfiguration) -> NSURLSession {
        return sharedInstance.createSessionWithConfiguration(configuration)
    }

    //MARK: - Private methods
    private func createSessionWithConfiguration (configuration:NSURLSessionConfiguration) -> NSURLSession {
        return NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }

    //MARK: - NSURLSessionDelegate protocol conformance
    public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        // Always called since it's the delegate of all NSURLSession created using createSessionWithConfiguration
    }
}

// Let create a NSURLSession object :
let session = SessionCreator.createSessionWithConfiguration(NSURLSessionConfiguration())
Michaël Azevedo
  • 3,874
  • 7
  • 31
  • 45
  • 1
    You can extends the NSURLSessionDelegate protocol for adding default implementation, but your NSURLSession objects needs a delegate. Nailed it. – Stephan Mar 15 '16 at 12:01