I am new to Swift and I am trying to use the optional binding feature in as efficient way as possible but I am a bit confused on how to use it (if I can) in this scenario:

var jsonData:AnyObject? = nil

jsonData = try? NSJSONSerialization.JSONObjectWithData(data!, options: [])
if(jsonData == nil) {
    print("Could not parse data")
}

if(httpresponse.statusCode == 200 || httpresponse.statusCode == 201) {
    if (jsonData as? ReturnType) != nil {
        return jsonData as? ReturnType
    } else { print("Request Successful") }
} else { // Not HTTP 200 or 201
    if let dic = jsonData as? NSDictionary {
        if dic["Message"] != nil && (dic["Message"] as? String) != nil {
            let message = dic["Message"]! as! String
            print("Server returned status code '\(httpresponse.statusCode)': '\(message.trim())'")
        }
    } else {
        let message = NSHTTPURLResponse.localizedStringForStatusCode(httpresponse.statusCode)
        print("Server returned status code '\(httpresponse.statusCode)': \"\(message)\"")
    }
}

The key statements here are:

jsonData = try? NSJSONSerialization.JSONObjectWithData(data!, options: [])
if(jsonData == nil) {
    print("Could not parse data")
}

There are potentially several places where all I need to do is a print or a user message (basically run some conditional code) after an important assign/unwrap without any major redirections of the rest of the code.

I was wondering if there was a smarter way of doing what I want to do without having to follow up each of those assignments with its own if statement.

I was under the impression that if let and guard did that very thing by merging conditional statements like if and else with the assignment, thus compacting the code, but they also seem to add some restrictive scope limitations like scope of the constant in the if let and having to 'return' or 'continue' in the guard scope.

What do you think?

  • 2
    Welcome to CR! Please edit your title to tell us what your code is doing see our How to Ask page for more info. – Mathieu Guindon May 5 '16 at 16:00
  • coming back to this later – nhgrif May 5 '16 at 16:21

To answer your explicit question with what is probably an obvious answer... Wrap it up in a function.

func debugSerialize(data: NSData) -> AnyObject? {
    let jsonData = try? NSJSONSerialization.JSONObjectWithData(data, options: [])
    if(jsonData == nil) {
        print("Could not parse data")
    }
    return jsonData
}

Another option would be to let NSJSONSerialization.JSONObjectWithDatas thrown error propagate up the stack and have a centralized place to catch them and put the print there... Unless you are married to the idea that the rest of your code must run even if jsonData is nil...

Keep in mind that most of the code you have posted does nothing but print debug output. Once the debugging is complete all of that code can, and should, be removed (don't leave a bunch of debugging print statements in production code.) Once you do that, you will see that all your code really does is check to see of the JSON deserialization created a ReturnType object.

Likely, you need this code to do more than produce debug output on bad server responses, but I'm not able to review hypothetical code that you could have written.

I think this would be more compact and safe way to handle this:

var jsonData:AnyObject? = nil
do {
    jsonData = try JSONSerialization.JSONObjectWithData(data!, options: [])
} catch {
    print("Could not parse data: \(error)")
    return nil
}

if(httpresponse.statusCode == 200 || httpresponse.statusCode == 201) {
    guard (jsonData as? ReturnType) != nil else {
        print("Request failed")//you mentioned 'Successful'
        return nil
    }
    return jsonData
} else { // Not HTTP 200 or 201
    guard let dic = jsonData as? [String:Any?], let errorMessage = dic["Message"]  as? String else {
        let message = HTTPURLResponse.localizedStringForStatusCode(httpresponse.statusCode)
        print("Server returned status code '\(httpresponse.statusCode)': \"\(message)\"")
        return nil
    }
    print("Server returned status code '\(httpresponse.statusCode)': '\(errorMessage.trim())'")
    return nil
}

this covers every case you may fall into!

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.