Damian Dudycz Damian Dudycz - 26 days ago 6
Swift Question

Correct handling session delegates

I want to make sure I'm implementing URLSessionTaskDelegate and URLSessionDataDelegate in correct way. I use them, because I want to be able to track the progress. This is the code so far:

final public fileprivate(set) var data: Data?
final public fileprivate(set) var response: URLResponse?
final public fileprivate(set) var error: Error?


public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
if let response = response as? HTTPURLResponse, response.statusCode == 200 {
data = Data()
}

self.response = response

completionHandler(.allow)
}

public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
self.data?.append(data)
}

public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
self.error = error

// ... Work with downloaded data
}


and a few questions:


  1. Should I always perform completionHandler in didReceive response, and should it always be .allow? Maybe I should only do this if response status code is 200?

  2. Is status code 200 the only one I need to really check for in this case and is this the right place to initialize the data? Maybe this function can be executed few times with different codes and I should treat any code differently?

  3. Is didCompleteWithError the only place I need to assign error? Maybe errors can be generated in different places too?

  4. In the documentation for URLResponse I can see the default value of expectedContentLength is NSURLResponseUnknownLength, but this value does not exist. Is there some new name for it now?

  5. Is there something else I should know so that this code is universal?


Rob Rob
Answer
  1. If the status code is not 200, often the body of the response includes information that helps you diagnose why it was not 200, so you probably want to continue to capture that information. I'd probably move that status code checking to didCompleteWithError.

  2. I generally expect 200 and thus only check for 200. Technically, all of the 2xx codes are "success" codes, so you might want to consider all of them successful. That's up to you.

  3. The didCompleteWithError is the only connection related error. Theoretically, you might want to check urlSession(_:didBecomeInvalidWithError:). Also, you might want to assign your own error code if you get a non-2xx status code or, at a higher level, if the parsing of the response failed.

  4. They don't appear to have defined an appropriate constant from Swift 3. FYI, looking at the headers, you can see the value is -1, but often we just check for response.expectedContentLength < 0.