JSONDecoder().decode fails when commas [closed] - json

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
The community is reviewing whether to reopen this question as of last year.
Improve this question
JSONDecoder().decode fails when there are commas at the end of a name field. Why is it happening? How can I solve it?
let string = "[{\"name\":\"Homeoffice Marc,\",\"Km\":846.7911330652549,\"Strid\": \"DE262B62633E34AAA8A622E189B42920B319C371\"},{\"name\":\"Küche,\",\"Km\":857.8694764184313,\"Strid\": \"BD1A60D736BE86377121A2CC713251DBE2603BD5\"},{\"name\":\"Besprechungszimmer,\",\"Km\":857.8721480885644,\"Strid\": \"751A10C5D3065F91CC9F5BDF5E7111DC452D1C39\"},{\"name\":\"Büro Vertrieb,\",\"Km\":857.8723091979339,\"Strid\": \"148F97F324BB59EAFF613A0EB3766E026CFAB320\"},{\"name\":\"Büro Produktmanagement und Support,\",\"Km\":857.8734889037903,\"Strid\": \"3A37C955F7D3C012577B1D19B6F662AD233372A5\"},{\"name\":\"Tischkicker,\",\"Km\":857.8748603133218,\"Strid\": \"B5B8A86BBA2102AF56721166D2E814736EF13132\"},{\"name\":\"Büro Entwicklung,\",\"Km\":857.8773683652697,\"Strid\": \"E6814BE03EEF386E63AD7609D970BD9BA8CE71AD\"},{\"name\":\"Syfit GmbH,\",\"Km\":857.877841443768,\"Strid\": \"64F80B1EC04D008E060F28D7F198A8C39DCD53B5\"},{\"name\":\"Büro Zolti,\",\"Km\":857.8798725612223,\"Strid\": \"23F4C2E1C467AEC9D55D873DC3ED7FC73CD92177\"},{\"name\":\"Globale Suche\",\"Km\":null,\"Km\":846.7911330652549}]"
let data = string.data(using: .utf8) ?? Data()
let areas = try? JSONDecoder().decode([AreaModel].self, from: data)
decoding this data returns nil
My model:
struct AreaModel: Codable {
enum CodingKeys: String, CodingKey {
case name
case km = "Km"
case strid = "Strid"
}
let name: String
let km: Double?
let strid: String
}

Please don't ignore thrown errors.
If you can't debug yourself, NEVER USE try?. With more experience, I'd say that we tend to not use try?, but sometimes we do. But when we write try?, we are able to find an possible issue, ie debug if needed.
Let's do a proper try then, with a do/catch:
do {
let areas = try JSONDecoder().decode([AreaModel].self, from: data)
print(areas)
} catch {
print("Error while decoding: \(error)") //and print error, not error.description which is for non-developer and will be missing important information
}
Which should output:
Error while decoding:
keyNotFound(CodingKeys(stringValue: "Strid", intValue: nil),
Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 9", intValue: 9)],
debugDescription: "No value associated with key CodingKeys(stringValue: \"Strid\", intValue: nil) (\"Strid\").", underlyingError: nil))
So, it's the 9th element of your JSON array that causes the issue.
It can't decode properly Strid value. There is no valid String value.
Let's see... You have {"name":"Globale Suche","Km":null,"Km":846.7911330652549}. In fact you have no Strid key here. Did you meant {"name":"Globale Suche","Strid":null,"Km":846.7911330652549}? Even if that's the case it's null, in other words, in Swift it would be nil. So to handle that case, you need to make Strid value optional
let strid: String?
Side note, the start of the answer if taken for another question of mine, so clearly not plagiarism.

Related

Swift - crash EXC_BAD_ACCESS JSONDecoder with large JSON [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm stuck on decoding a JSON in swift.
I've got the following code in a playground with a JSON that has 10 fields. When i try to decode the data I get the following Error
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=EXC_I386_GPFLT).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
But this error does not seem to happen if I take out e.g. "ninth" and "tenth" or 2 of any of the other fields so only 8 fields remain in the struct.
Is there a limitation of only be able to have 8 fields decoded? Am I missing something?
is there anything i can do to overcome this issue?
My code snippet:
let decoder = JSONDecoder()
struct Positions: Codable {
let first : String
let second: String
let third: String
let forth: String
let fith: String
let sixth: String
let seventh: String
let eigth: String
let nineth: String
let tenth: String
}
var positions = """
{
"first" : "first",
"second": "second",
"third": "third",
"forth": "forth",
"fith": "fith",
"sixth": "sixth",
"seventh": "seventh",
"eigth": "eigth",
"nineth": "nineth",
"tenth": "tenth"
}
""".data(using: .utf8)
let result = try decoder.decode(Positions.self, from: positions!)
print("tr \(result)")

Decode nested JSON child with Decodable [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
The new Swift "Decoder" class sounds like a great way to parse JSON data, but all of the examples I've found use a well-known, well-defined 'struct' to do so.
In my case I'm querying an arbitrary website that returns a HUGE JSON string and I only care about a few of the (deeply nested) fields, so I don't want to take all that time to define a 'struct' to get at them.
Is it even possible to do this with "Decoder"? And if so, how does one go about it?
The question seems to be based on a misapprehension about how Decodable works. As a convenience, Decodable is willing to do some automatic code generation behind the scenes so that you can define a struct or nest of structs and just decode the entirety of the JSON. But you are not required to take advantage of that in order to decode JSON.
There is no need to define struct properties for "fields" you don't care about. If a JSON dictionary contains 100 keys and your corresponding struct contains just one property, no problem; that key will be fetched, and no others.
With regard to the "deeply nested" part, it should not take you much time to write simple nested structs that perform the dive to reach the dictionary you really care about. But if you don't want to do even that, you could write an implementation of init(from:) that dives down and fetches out the desired values.
In other words, if you think of Decodable as consisting primarily of your implementation of init(from:), and learn to write the code that it needs, you will see that this JSON can be parsed in a few quick simple lines of code.
As an example, here's a JSON sketch of a deeply nested piece of information with a bunch of extra information at every level that we want to ignore:
{
"ignore": true,
"outer1": {
"ignore": true,
"outer2": {
"ignore": true,
"outer3": {
"name": "matt",
"ignore": true
}
}
}
}
What I'd like to do is define a very simple struct Person that consists solely of the deeply nested name:
struct Person : Decodable {
let name : String
}
I can do that! To do so, I implement Decodable myself, supplying a "hoover" CodingKey adopter struct and an implementation of init(from:), like this (this may look like a lot of work, but it isn't, because the AnyCodingKey implementation is boilerplate, copied and pasted from here, and the init(coder:) implementation is just a few lines of code that were easy to write):
struct Person : Decodable {
let name : String
struct AnyCodingKey : CodingKey {
var stringValue: String
var intValue: Int?
init(_ codingKey: CodingKey) {
self.stringValue = codingKey.stringValue
self.intValue = codingKey.intValue
}
init(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
init(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
init(from decoder: Decoder) throws {
var con = try! decoder.container(keyedBy: AnyCodingKey.self)
con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer1"))
con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer2"))
con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer3"))
let name = try! con.decode(String.self, forKey: AnyCodingKey(stringValue:"name"))
self.name = name
}
}
When I want to dive into the JSON and grab the name information, it's trivial:
let person = try! JSONDecoder().decode(Person.self, from: json)
The result is a Person object with name value "matt". Note that I didn't have to add any of the ignore keys and I didn't need to make a nest of structs.
Sure you can achieve this but with both JSonSerialization & Decodable , you have to serialize the json until reach the desired content then decode it ,but instead I recommend to create structs for root keys only then decode , think of it as it's a path from top to bottom don't decode a key that isn't in the path of your desired content

Swift JSON Serialization typeMismatch

Currently struggling how to use Decodable. I've done some googling to the errors I'm getting but I still believe that the way i'm structuring the structs isn't correct but it seems to make sense to me.
I've also tried using optionals
In the error that I've posted at the end, I'm confused about the reference to the Double type. As I don't have any type or anything int he response that uses a double.
(I'm also able to serialize the json reponse using the old swift method of casting the data as dictionaries - [String : Any]. But I'd like to use the modern/updated approach.)
JSON Response
{"NEWS":
[
{
"DATE":"2018-10-13T03:56:06+1000",
"SOURCE":"smh.com.au",
"BLURB":"Assistant Treasurer Stuart Robert says he has repaid $37,975 of \"excess usage charges\" in home internet bills footed by taxpayers.",
"ID":102347,
"TITLE":"Stuart Robert pays back $38,000 in excessive home internet charges"
},
{
"DATE":"2018-10-12T18:00:38+1000",
"SOURCE":"itwire.com",
"BLURB":"The CVC costs set by the NBN Co make it very difficult for ISPs to offer gigabit connections to more than a select band of customers who are willing to sign up in numbers and pay slightly more than other speed tiers, according to one ISP who caters to this type of consumer.",
"ID":102343,
"TITLE":"NBN gigabit connections will remain mostly a pipe dream"},
{
"DATE":"2018-10-12T09:48:43+1000",
"SOURCE":"computerworld.com.au",
"BLURB":"The Department of Home Affairs has rejects calls to include independent judicial oversight of the decision to issue Technical Assistance Notices and Technical Capability Notices as part of proposed legislation intended to tackle police agencies’ inability to access encrypted communications services.",
"ID":102342,
"TITLE":"Home Affairs rejects calls for additional safeguards in ‘spyware’ law"
},
{
"DATE":"2018-10-11T12:16:05+1000",
"SOURCE":"itnews.com.au",
"BLURB":"NBN Co is hoping to “speed up” building works on the fibre-to-the-curb (FTTC) portion of its network as it tries to make up lost ground.",
"ID":102334,
"TITLE":"NBN Co says fibre-to-the-curb build is more complex that it hoped"
},
]
}
CODE
struct Root: Decodable {
let news: [News]?
enum CodingKeys: String, CodingKey {
case news = "NEWS"
}
}
struct News: Decodable {
let date: Date
let source, blurb: String
let id: Int
let title: String
enum CodingKeys: String, CodingKey {
case date = "DATE"
case source = "SOURCE"
case blurb = "BLURB"
case id = "ID"
case title = "TITLE"
}
}
Serialization
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let dataStr = data else {
return
}
do {
let root = try JSONDecoder().decode(Root.self, from: dataStr) //error is caught here
guard let r = root else { return }
print(r.news)
} catch let err {
print("JSON Error - \(err)")
}
}.resume()
Error
error serializing json typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "NEWS", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "DATE", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))
This is because the default coding strategy for Date is double (seconds since epoch). You can change the default strategy to iso8061 or anything custom. For example, you can set the date formatter in your decoder like so:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
Putting the JSON into Quicktype gives me an extra comma error. Unless there's more nodes to the json file? So make sure about that first. At first glance, I could be wrong, but I think you have to format the DATE to exactly match.

Swift 4: JSONDecoder fails in one specific case - "The operation could not be completed" [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I am receiving JSON text, converting it to Data, and then using JSONDecoder to create a concrete type represented by the JSON text/string.
It does work with my "complex" data structure (which implements Codable), or even a simple array of Int as shown below:
import Foundation
let jsonTextContainigArrayOfInt: String = "[1,2,3]"
let data = jsonTextContainigArrayOfInt.data(using: .utf8)!
do {
let arrayOfInt: [Int] = try JSONDecoder().decode([Int].self, from: data)
for n in arrayOfInt {
print(n)
}
}
catch {
print(error)
}
The previous code works and correctly creates the array of Int and prints them.
The problem occurs when doing this same approach with a single Int in the JSON-text:
import Foundation
let jsonTextContainigOneInt: String = "1"
let data = jsonTextContainigOneInt.data(using: .utf8)!
do {
let myInt: Int = try JSONDecoder().decode(Int.self, from: data)
print(myInt)
}
catch {
print(error)
}
For this second approach, I get the following error:
"The operation could not be completed"
*** Edit ***
Bug report for this already exists: https://bugs.swift.org/browse/SR-6163
JSONDecoder can only decode a collection type (array or dictionary) as root object.
Under the hood JSONDecoder uses JSONSerialization without any options. However to decode a String or Int you have to specify the .allowFragments option.
Use JSONSerialization with the .allowFragments option
let jsonTextContainingOneString = "1"
let data = Data(jsonTextContainingOneString.utf8)
do {
let myString = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(myString)
}
catch {
print(error)
}
Interesting... I found this:
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/JSONSerialization.swift#L120
Specifically this guard statement:
open class JSONSerialization : NSObject {
//...
// top level object must be an Swift.Array or Swift.Dictionary
guard obj is [Any?] || obj is [String: Any?] else {
return false
}
//...
}
Then I looked if a simple text-string should be considered valid JSON, and apparently it should now (it was previously not accepted as valid JSON). At least, based on this excellent answer: https://stackoverflow.com/a/7487892/8284660
This makes me wonder whether or not the behavior on my original post should be a bug or not.

How do you design a codable JSON field which can be either an empty string or an int [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
How do you handle a field of a codable struct from JSON which can be either an empty string or an int? I tried using the data type any but that does not conform to codable. I think that if it does not have a value then it returns an empty string or otherwise, it returns an int. I am using Swift 4 and XCode 9. Thanks in advance
I really would suggest changing that web service to return values consistently (and if there is no value for the integer type, don't return anything for that key).
But if you're stuck with this design, you will have to write your own init(from:) which gracefully handles the failure to parse the integer value. E.g.:
struct Person: Codable {
let name: String
let age: Int?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
do {
age = try values.decode(Int.self, forKey: .age)
} catch {
age = nil
}
}
}
I'd also advise against using 0 as a sentinel value for "no integer value provided". This is what optionals are for.