AndreG AndreG - 3 years ago 99
Swift Question

Swift 3.0 down casting and best practices

My question here is mostly in trying to be a better programmer, not that my code doesn't work.

Is downcasting something considered good enough (as in 'best practices') when writing your code? I'll give an example below with URLSession. I understand Swift gives you the tools to do it with as! or as?, but something tells me we shouldn't be doing it (or there are better ways to do it). I just can't see them. For example, consider this code that retrieves a web page from a HTTP GET request:

let UrlString = "https://www.google.com"
guard let url = URL(string: UrlString) else {
return nil
}
if let scheme = url.scheme {
if scheme != "http" || scheme != "https" {
return nil
}
}

URLSession.shared.dataTask(with: url) { (d, r, e) in
if let error = e {
print(error)
}
else {
guard let request = r as? HTTPURLResponse else {
return
}
let statusCode = request.statusCode
let contentType = request.allHeaderFields["Content-Type"] as! String
let dataString = String(data: d!, encoding: .utf8) ?? nil
return
}
}.resume()


So, the above code works, but my question is on the
guard let request = r as? HTTPURLResponse
statement.
dataTask
is supposed to return an
URLResponse
object back to the delegate, in this case, my variable
r
. However, this class obviously doesn't have a status code. So if I do the following, Swift will give me a compile error:

guard let request = r else {
return nil
}
statusCode = request.statusCode


Because request is supposed to be an URLResponse object, so it fails Xcode's check.

In order to obtain that information I need to either force down casting to HTTPURLResponse with as! (I've checked that the request is http/https earlier) or check with an optional as I did above.

Now , I don't want to use big wrappers like Alamofire because my API is very very simple. I want to write my own wrapper around URLResponse and return an object that other parts of my code can use. I don't know how the AF guys solve this problem. What would be the Swift way of dealing with this? Is down casting fine as a "best practice"? Is there a better way of getting the HTTPURLRequest object?

Answer Source

First of all, strictly spokenĀ a block based API doesn't have a delegate.

URLSessionDataTask is a quite versatile class and can be used for other purposes than an HTTP request hence the response object is the more generic URLResponse class and it is optional.

In case of an HTTP request the API returns the more specific subclass HTTPURLResponse so the object must be casted down to get access to the specific properties of HTTPURLResponse like statusCode. So yes, down casting is fine as a "best practice".

Here are two suggestions to be a better programmer

  1. Variable names are supposed to start with a lowercase letter e.g. urlString
  2. As already mentioned in a comment use more descriptive variable names than a single character.

There is another serious error in the code: The completion handler has no return value so you will get a compiler error Unexpected non-void return value in void function.

Side-note: The check for the scheme and for nil is not needed since the literal string https://www.google.com clearly contains the scheme and is a valid URL.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download