17

I'm using the most recent version of Xcode (8.1 at time of writing), which uses Swift 3.0.

All I'm trying to do is take a string, convert it to a URL and test that URL to see if it gives me a 404 error. I've been able to make a URL and URLRequest by using:

    let url = URL(string: fullURL)
    let request = URLRequest(url: url!)

but I've found myself unable to get anything working beyond that. I've searched around for help, but most, if not all of it, is written in Swift 2.0, which I've tried to convert to no avail. It seems that even if you change the naming convention to remove the NS prefix, that isn't enough. I tried using:

    let response: AutoreleasingUnsafeMutablePointer<URLRequest> = nil

but that gives me an error that "fix-it" makes worse by sticking question marks and semi-colons everywhere.

Apple's documentation isn't helping me much, either. I'm seriously at a loss.

Does anybody know how to correctly set up and test a URL for 404 status in Swift 3.0?

DisturbedNeo
  • 713
  • 2
  • 5
  • 19
  • http://stackoverflow.com/a/39099896/1801544 ? – Larme Nov 02 '16 at 14:32
  • you might want to check [this](http://stackoverflow.com/questions/26634539/swift-downcast-nsurlresponse-to-nshttpurlresponse-in-order-to-get-response-cod) – Ahmad F Nov 02 '16 at 14:46

3 Answers3

40

try this out to give you the status codes of the responses - 200, 404 etc:

let url = URL(string: fullURL)

let task = URLSession.shared.dataTask(with: url!) { _, response, _ in
    if let httpResponse = response as? HTTPURLResponse {
        print(httpResponse.statusCode)
    }
}

task.resume()

You could also do the same, simply replacing the with: url! to use the request var as you defined in your example e.g. let task = URLSession.shared.dataTask(with: request) {...} But in this example I don't think you need to really.

Matt Le Fleur
  • 2,708
  • 29
  • 40
  • Well, it runs without crashing, but it never reaches "if let httpResponse = response as? HTTPURLResponse", so it never prints the status code. – DisturbedNeo Nov 02 '16 at 16:11
  • @DisturbedNeo it may be something to do with the url itself. If there's no server name with the specified hostname of the url you won't even get a 404 error. Try adding `error` after the response so you get something like `{ _, response, error in ` and then try printing the error to see what you're getting – Matt Le Fleur Nov 02 '16 at 16:50
  • If you're getting something like `"A server with the specified hostname could not be found."` that would indicate a server side issue. – Matt Le Fleur Nov 02 '16 at 16:54
  • There's all sorts of other errors such as `"The Internet connection appears to be offline."`, and all of these would cause the response to fail as you mentioned. – Matt Le Fleur Nov 02 '16 at 16:59
  • That's the thing though, I can't get any errors to print, it never goes inside the scope of the task. It does "let task = URLSession.shared.dataTask(with: url!) { _, response, error in", then skips over it to task.resume(). I put a breakpoint on the if and the loop to check different URLs ran 100 times but never once hit the breakpoint. – DisturbedNeo Nov 02 '16 at 17:10
  • How or where are you using this code from? For testing I've put all of this inside the `viewDidLoad` and seems to work fine, so perhaps you doing this in a different way is the reason? – Matt Le Fleur Nov 02 '16 at 17:32
  • Maybe. My code isn't in viewDidLoad because there's no view, this is just code running in main.swift. At the moment, the program is supposed to start, run a for loop, inside which it prints the URL it's checking, performs the check and then reports whether or not that URL was a 404. I don't see why the code being in a separate function should change anything, but then Xcode never has made any sense. Thanks anyway. – DisturbedNeo Nov 02 '16 at 17:51
  • Found the problem, it's because I was checking many URLs in a for loop, so basically I wasn't giving it enough time to respond. Putting in sleep(1) or at the very least usleep(500000) just before task.resume() was long enough to reliably get status codes from each URL. Thanks for all your help ^_^ – DisturbedNeo Nov 03 '16 at 12:10
  • No problem, glad you managed to get it working! I'd suggest using something other than sleep though as that sounds a bit unreliable! Perhaps ave a look into GCD and synchronous requests / completion handlers :) – Matt Le Fleur Nov 03 '16 at 12:19
  • @DisturbedNeo can you mark this as the accepted answer if you're happy with it still? :) just to make clarity when people search for the same question – Matt Le Fleur Aug 09 '19 at 15:22
9

Simple example:

    let url = // whatever
    let session = URLSession.shared
    let task = session.downloadTask(with:url) { loc, resp, err in
        let status = (resp as! HTTPURLResponse).statusCode
        print("response status: \(status)")
    }
    task.resume()
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 3
    Never use the force unwrap (as!) without checking the value is not nil. Otherwise the app will crash – OxyFlax Jun 14 '18 at 08:06
  • 1
    @OxyFlax you should force unwrap if you are certain of the value, that's what it's there for. – Patrick Mar 08 '21 at 06:01
3

Here is one more example from delegate method

public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didBecome downloadTask: URLSessionDownloadTask){

let responseStatusCode = (dataTask.response as! HTTPURLResponse).statusCode
}

Here is the example https://github.com/ankitthakur/SwiftNetwork/blob/master/Sources/Shared/SwiftNetwork.swift

Ankit Thakur
  • 4,739
  • 1
  • 19
  • 35