-
Notifications
You must be signed in to change notification settings - Fork 40
Working with URLSession
There are many considerations for the networking stack in your application. Given the breadth of these considerations, we didn't want a one-size-fits-all route for doing networking in Deferred. For instance, using URLSessionDelegate disables the convenience callback methods like URLSession.dataTask(with:completionHandler:) that would be used by a built-in solution to Deferred.
That said, the new Task module to Deferred provides a great opportunity for tying together the two parts.
extension NSURLSession {
/// Returns the data from the contents of a URL, based on `request`, as a
/// future.
///
/// The session bypasses delegate methods for result delivery. Delegate
/// methods for handling authentication challenges are still called.
///
/// - parameter request: Object that provides the URL, body data, and so on.
/// - parameter configure: An optional callback for setting properties on
/// the URL task.
func beginDataTask(with request: NSURLRequest) rethrows -> Task<(NSData, NSURLResponse)> {
let deferred = Deferred<Task<(NSData, NSURLResponse)>.Result>()
let task = dataTaskWithRequest(request) { (data, response, error) in
if let error = error {
deferred.fail(error)
} else if let data = data, let response = response {
deferred.succeed((data, response))
} else {
deferred.fail(NSURLError.BadServerResponse)
}
}
defer { task.resume() }
return Task(deferred, cancellation: task.cancel)
}
}This approach notably doesn't include progress reporting or any other advanced use of URLSessionTask.
URLSessionTask instances can be observed in isolation, without their completion callbacks, using Key-Value Observing.
A vital lesson for maintaining a class that implements URLSessionDelegate is that URLSession instances are self-contained. The taskIdentifier property is unique for tasks in a session, and thus are useful for tracking constituent tasks.
A full-blown solution would be integrated into a network manager class that conforms to URLSessionDelegate. Consider the pseudocode below.
final class MyURLClient: NSObject, URLSessionTaskDelegate {
private final class TaskState: NSObject {
...
}
private let urlSession: URLSession
private var tasks = [Int: TaskState]()
func URLSession(session: URLSession, didBecomeInvalidWithError error: NSError?) {
tasks.removeAll()
}
func URLSession(session: URLSession, task: URLSessionTask, didCompleteWithError error: NSError?) {
guard let state = tasks.removeValue(forKey: task.taskIdentifier) else { return }
// use `state`
}
func URLSession(session: URLSession, dataTask task: NSURLSessionDataTask, didReceive response: URLResponse, completionHandler: URLSessionResponseDisposition -> Void) {
state[task.taskIdentifier] = TaskState(...)
completionHandler(.Allow)
}
}© 2014-2018 under MIT. Brought to you by your friends at Big Nerd Ranch.