2

I have a problem with a Codable parsing... that's my example code:

class Test: Codable {
      let resultCount: Int?
      let quote: String?
}

 var json =  """
{
    "resultCount" : 42,
    "quote" : "My real quote"
}
""".data(using: .utf8)!

 var decoder = JSONDecoder()
 let testDecoded = try! decoder.decode(Test.self, from: json)

Here everything works as expected and the Test object is created.

Now my back end sends me the quote string with a quote in the middle... in this form (please note \"real\"):

class Test: Codable {
      let resultCount: Int?
      let quote: String?
}

 var json =  """
{
    "resultCount" : 42,
    "quote" : "My \"real\" quote"
}
""".data(using: .utf8)!

 var decoder = JSONDecoder()
 let testDecoded = try! decoder.decode(Test.self, from: json)

In this second case the decoder fails to create the object... and that's my error message:

dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 4." UserInfo={NSDebugDescription=No string key for value in object around character 4.})))

Is there a way to solve this issue?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
DungeonDev
  • 1,176
  • 1
  • 12
  • 16
  • 5
    Embedded quotes in JSON must be escaped. In your string literal that would be `"My \\"real\\" quote"` – Martin R Jan 04 '19 at 14:50
  • You need to use `\\ ` in a String literal to escape a `"`. With a String like that, your code works just fine. Is your backend sending a real JSON with escaped quotes? You should put the actual JSON in a file to get around the double escaping you need to do in String literals and test with that to mimic the backend. – Dávid Pásztor Jan 04 '19 at 14:52

1 Answers1

2

To include quotation marks in your JSON there have to be actual \ characters before the quotation marks within the string:

{
    "resultCount" : 42,
    "quote" : "My \"real\" quote"
}

To do that in Swift string literal, you need to escape the \. That results in "My \\"real\\" quote" within the Swift multi-line string literal:

let json = """
    {
        "resultCount" : 42,
        "quote" : "My \\"real\\" quote"
    }
    """.data(using: .utf8)!

let decoder = JSONDecoder()
let testDecoded = try! decoder.decode(Test.self, from: json)

However, if dealing with a standard, non-multiline string literal, you need to escape both the backslash and the quotation mark, resulting in even more confusing looking \"My \\\"real\\\" quote\":

let json = "{\"resultCount\": 42, \"quote\" : \"My \\\"real\\\" quote\"}"
    .data(using: .utf8)!
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you! ...and thank you to anyone else. So the problem was in the string literal and not in the JSON itself from the backend service (the iTunes API uses the same quotation in many fields). – DungeonDev Jan 04 '19 at 15:30