Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Network Programming with Swift 2 Protocol Oriented Networking Completing JSONTaskWithRequest

Christopher Bonuel
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Christopher Bonuel
iOS Development Techdegree Graduate 14,116 Points

Why is the 'if-else' block written the way it is?

The way it is written makes 'data' force unwrapped inside the else clause

if data == nil {
    if let error = error {
        completion(nil, HTTPResponse, error)
    }
} else {
    switch HTTPResponse.statusCode {
    case 200:
        do {
            let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String : AnyObject]
            completion(json, HTTPResponse, nil)
        } catch let error as NSError {
            completion(nil, HTTPResponse, error)
        }
    default: print("Received HTTP Response: \(HTTPResponse.statusCode) - not handled")
    }
}

Why did Pasan choose not to write it like this instead?

if let data = data {
    switch HTTPResponse.statusCode {
    case 200:
        do {
            let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String : AnyObject]
            completion(json, HTTPResponse, nil)
        } catch let error as NSError {
            completion(nil, HTTPResponse, error)
        }
    default: print("Received HTTP Response: \(HTTPResponse.statusCode) - not handled")
    }
} else {
    if let error = error {
        completion(nil, HTTPResponse, error)
    }
}

Is it because it's better to have all the error-handling code above the one success case?

3 Answers

Connor Crawford
Connor Crawford
6,405 Points

I think the most simple answer that I see and can give you is that you have to check to see if data is nil first as a safety method. This is the first block that Pasan writes where he checks if the data is nil and if it is then perform error handling and if it isn't then switch over the success case to perform some operation. First thing he does is safely check for nil being passed through because we don't want that, a very important step in Network Programming.

Christopher Bonuel, the data object is optional, but since we have already ensured that it can't be nil inside our else clause, we can safely unwrap it without causing a runtime error. Remember the 200 status code is where we end up if the request has succeeds with no issues. I hope that this helps.

David Lin
David Lin
35,864 Points

Here's my solution using guard for the data check that eliminates the if-then nesting:

func JSONTaskWithRequest(request: NSURLRequest, completion: JSONTaskCompletion) -> JSONTask {

    let task = session.dataTaskWithRequest(request) {
        data, response, error in

        guard let HTTPResponse = response as? NSHTTPURLResponse else {
            let userInfo = [
                NSLocalizedDescriptionKey: NSLocalizedString("Missing HTTP Response", comment: "")
            ]

            let error = NSError(domain: NETWORKING_ERROR_DOMAIN, code: MISSING_HTTP_RESPONSE_ERROR, userInfo: userInfo)
            completion(nil, nil, error)
            return
        }

        guard let data = data else {
            if let error = error {
                completion(nil, HTTPResponse, error)
            }
            return
        }

        switch HTTPResponse.statusCode {
        case 200:
            do {
                let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? JSON
                completion(json, HTTPResponse, nil)
            } catch let error as NSError {
                completion(nil, HTTPResponse, error)
            }
        default: print("Received HTTP Response: \(HTTPResponse.statusCode) - not handled")
        }
    }

    return task
}