Stuart Breckenridge

Completion Handlers vs. Delegation with URLSession

I am currently working on a URL shortener side project that uses URLSession and it just so happens that over on Use Your Loaf Keith Harrison was examining the same problem as me: completion handlers or delegation.

My initial API for shortening URLs used a completion handler:

public func shortenURL(url:String, completionHandler:@escaping (Bool, String?) -> ()) throws {
	// Setup Code  //
	let session = URLSession(configuration: .default, delegate: nil, delegateQueue: nil)
	let task = session.dataTask(with: urlComponents.url!, completionHandler: {(data, response, error) in
            if data != nil && error == nil {
                do {
                    let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
                    
                    guard let shortenedURL = json["shorturl"] as? String else {
                        completionHandler(false, nil)
                        return
                    }
                    
                    completionHandler(true, shortenedURL)
                } catch {
                    completionHandler(false, error.localizedDescription)
                }
            }
        })
    task.resume()
}

This worked fine, but I still prefer to use delegation when using URLSession:

public func shortenURL(url:String) throws {
	// Request did begin
	self.delegate?.didBeginRequest()
	
	// Setup Code //
	
	let session = URLSession(configuration: .default, delegate: nil, delegateQueue: nil)
        let task = session.dataTask(with: urlComponents.url!, completionHandler: {(data, response, error) in
            if data != nil && error == nil {
                do {
                    let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
                    
                    guard let shortenedURL = json["shorturl"] as? String else {
                        DispatchQueue.main.async {
                            self.delegate?.didFailWith(error: nil)
                        }
                        return
                    }
                    
                    DispatchQueue.main.async {
                        self.delegate?.didShortenTo(url: shortenedURL)
                    }
                } catch {
                    DispatchQueue.main.async {
                        self.delegate?.didFailWith(error: error)
                    }
                }
            }
        })
    task.resume()
}

Why delegation? URLSession doesn’t have a didBeginRequest() equivalent and I like having that granular level of control.


— Supported by —