0

I'm trying to get header information from distant URL with Swift 5 but it doesn't work. Could you help me please?

func getHeaderInformations (myUrl: URL) -> String {
    var content= ""
    var request = URLRequest(url: myUrl)
    request.httpMethod = "HEAD"

    let task = URLSession.shared.dataTask(with: request, completionHandler: {data, response, error in
        if let reponse = response as? HTTPURLResponse {
            let contentType = reponse.allHeaderFields["Content-Type"]
            let contentLength = reponse.allHeaderFields["Content-Length"]
            content = String(describing: contentType) + "/" + String(describing: contentLength)
        }
    })
    task.resume()

    return content
}
koen
  • 5,383
  • 7
  • 50
  • 89
jordy
  • 31
  • 4

1 Answers1

0

The problem here is that task is executed asynchronously, so your getHeaderInformations function exits before content is ever set. (The block that sets content will be called some time later when the network request completes. You should also check the error parameter passed into this block, because at the moment you'll never know if there is an error.

You basically have two options:

  1. If you're not running on the main thread, you could convert getHeaderInformations to be synchronous. See Can I somehow do a synchronous HTTP request via NSURLSession in Swift for how to do that.
  2. Otherwise, you can convert the code that calls getHeaderInformations to also be asynchronous. To do that you would do something like the following.

Somewhere in your code you call getHeaderInformations and do something with the result.

 let header = getHeaderInformations(myUrl: someURL)
 // Do something with header...

Instead you rewrite getHeaderInformation to look like this:

func getHeaderInformations (myUrl: URL, completionHandler: @escaping (_ content: String, _ error: Error?) -> Void) -> Void {
    var request = URLRequest(url: myUrl)
    request.httpMethod = "HEAD"
    let task = URLSession.shared.dataTask(with: request) {data, response, error in
        if let reponse = response as? HTTPURLResponse{
            let contentType = reponse.allHeaderFields["Content-Type"]
            let contentLength = reponse.allHeaderFields["Content-Length"]
            let content = String(describing: contentType) + "/" + String(describing: contentLength)
            completionHandler(content, error)
        }
    }
    task.resume()
}

This adds a completion handler which will be called when the network request finishes. You would then alter the code that calls it to look like this:

    getHeaderInformations(myUrl: url)  { header, error in
        guard let unwrappedError = error else {
            // handle error
            return
        }
        // do something with header...
    }

Note: I'm using trailing closure syntax here which you did not use in your example. If you're not sure about it see Trailing Closures

idz
  • 12,825
  • 1
  • 29
  • 40