How to implement NSURLSession delegate using SWIFT

In previous post How to write SWIFT code to make HTTP GET request, I showed a very simple code demonstrating simple concepts. In this post I will build on top of the previous simple code and show how to implement a custom delegate for NSURLSession tasks.

In previous sample, I used self to implement all delegate methods. But in real life application, you are going to need some generic implementation of delegates to handle HTTP requests. To implement a custom delegate that you will create a new class that implements delegate methods from NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate protocols. You don't have to implement all the protocols. Depending on type of session tasks you are executing, you can implement protocols specific to those type of session tasks only.

Custom NSURLSession Delegate


/*:
# Simple delegate for NSURLSession related request/response mechanism
Create new instance for each session task.
*/
public class ApiRequestDelegate:NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate,
    NSURLSessionDataDelegate{
    public var requestTime:NSTimeInterval?
    public var response:HttpResponse?
    var completionHandler:((HttpResponse) -> Void)?

    /*:
    This delegate method is called once when response is recieved. This is the place where
    you can perform initialization or other related tasks before start recieviing data
    from response
    */
    public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
       didReceiveResponse response: NSURLResponse,
       completionHandler: (NSURLSessionResponseDisposition) -> Void) {
        print("Session received first response!")
        self.response = HttpResponse(response: response as! NSHTTPURLResponse)
        // It is necessary to call completionHandler, otherwise request
        // will not progress one way or the other
        completionHandler(NSURLSessionResponseDisposition.Allow)
    }
    /*:
    This delegate method is called when session task is finished. Check for presence
    of NSError object to decide if call was successful or not
    */
    public func URLSession(session: NSURLSession, task: NSURLSessionTask,
        didCompleteWithError error: NSError?) {
        // When session task is complete, this delegate method will be called.
        // If there is no error then NSError object will nil, otherwise NSError
        // will contain information about the error.
        if let errorInfo = error{
            print("Session error: \(errorInfo.description)")
            self.response?.error = error
        }
        else{
            print("Request - complete!")
            self.response?.responseUrl = task.response?.URL
            self.response?.statusCode = (task.response as! NSHTTPURLResponse).statusCode
        }
        if let compHandler = completionHandler{
            compHandler(self.response!)
        }
    }
    /*:
    This delegate method is called when response data is recieved in chunks or
    in one shot.
    */
    public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
        didReceiveData data: NSData) {
        response?.responseData.appendData(data)
    }
}

In this sample class I only implemented bare minimum required methods for a simple GET request. This class allows caller to specify a completion handler method. This method will be called when GET request finishes. If you do not wish to be notified when request is complete, you do not have to specify this completion handler.

How to use custom delegate

I have modified implementation from previous post to use this new class as delegate instead of specifying self as delegate.

    public func heartBeat(){
        print("heartBeat - Start")
        let url = NSURL(string:"https://www.google.com")
        print("Request url is: \(url)!")
        // Step0: Create request object.
        let request = NSMutableURLRequest(URL:url!)
        // Step1: Create configuration
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        // Step2: Create session object with appropriate configuration, delegate and delegate queue
        let sessionDelegate = ApiRequestDelegate()
        sessionDelegate.completionHandler = heartBeatComplete
        let session = NSURLSession(configuration: configuration, delegate: sessionDelegate, 
        delegateQueue: NSOperationQueue.mainQueue())
        // Step3: Create session task
        let sessionTask = session.dataTaskWithRequest(request)
        requestStartTime = NSDate()
        sessionTask.resume()
    }
    
    public func heartBeatComplete(response:HttpResponse)->Void{
        if (response.error != nil){
            // Process error
            print(response.error!.description)
        }
        else{
            // Process response data
            print("Total downloaded data \(response.responseData)")
        }
    }

In subsequent posts I will build on these samples to demonstrate more network related concepts.

comments powered by Disqus

Blog Tags