5
\$\begingroup\$

Here's a quick extension for [String: AnyObject] dictionaries in Swift. The output needs to be in the following format (order and spacing don't matter):

{"key": "val", "keywdict": {"anotherKey": 100, "Key2": "Val2"}, "strings": ["string", "another"]}

I am wondering if there's a better way, or if this can be improved.

extension Dictionary //...

func toJSONString() -> String {
  var pcs = [String]()
  for (key, val) in self {
    var valStr = ""
    if let val = val as? String {
      valStr = "\"\(val)\""
    } else if let val = val as? Dictionary<String, AnyObject> {
      valStr = val.toJSONString() // recursion for nested dictionaries
    } else if let val = val as? Array<String> {
      let tmpStr = "\",\"".join(val)
      valStr = "[\"\(tmpStr)\"]"
    } else if let val = val as? NSNumber {
      valStr = "\(val)"
    }
    pcs.append("\"\(key)\":\(valStr)")
  }
  return "{" + ",".join(pcs) + "}"
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to CodeReview, Andrew. I hope you get some fine answers. \$\endgroup\$
    – Legato
    Apr 17, 2015 at 16:27

1 Answer 1

5
\$\begingroup\$

Your dictionary to JSON converter has some serious issues:

  • The special characters " and \in strings are not properly escaped:

    [ "a\"b" : "c\\d"].toJSONString()
    

    produces "{"a"b":"c\d"}", correct would be {"a\"b":"c\\d"} (see for example http://json.org).

  • Only arrays of strings are implemented, but not arrays of numbers or arrays of arrays or dictionaries.
  • Value types which are not covered by your code just print as an empty string instead of causing an error.
  • Boolean values are simply treated as numbers:

    [ "key" : true].toJSONString()
    

    gives {"key":1}, correct would be {"key":true}

While this could all be fixed, it probably isn't worth the effort because there is a Foundation class NSJSONSerialization which already does exactly this:

var dict : [String: AnyObject] = [:]
dict["a\"b"] = "c\\d"
dict["strings"] = ["string", "another"]
dict["keywdict"] = [ "anotherKey": 100, "Key2": "Val2"]
dict["numbers"] = [ 1, 2, 3]
dict["bools"] = [ true, false]

var error : NSError?
if let jsonData = NSJSONSerialization.dataWithJSONObject(dict, options: nil, error: &error) {
    let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String
    println(jsonString)
} else {
    println("Error in JSON conversion: \(error!.localizedDescription)")
}

Output:

{"keywdict":{"anotherKey":100,"Key2":"Val2"},"bools":[true,false],"a\"b":"c\\d","strings":["string","another"],"numbers":[1,2,3]}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the input, @Martin R. For my implementation (which I should have stated) I knew that I only needed to handle [String] arrays and numerics, though I totally goofed on escaping characters! The NSJSONSerialization implementation is CLEARLY the better solution, and I totally missed it. Thanks again. \$\endgroup\$ Apr 17, 2015 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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