0

I am trying to create some structs to decode some JSON received from an API using JSONSerialization.jsonObject(with: data, options: [])

This is what the JSON looks like:

{"books":[{"title":"The Fountainhead.","author":"Ayn Ranyd"},{"title":"Tom Sawyer","author":"Mark Twain"},{"title":"Warhol","author":"Blake Gopnik"}]}

Here are the structs that I am trying to use for decoding.

struct BooksReturned : Codable {
        let books : [Book]?
    }
    struct Book : Codable {
        let BookParts: Array<Any>?
    }
    struct BookParts : Codable {
        let titleDict : Dictionary<String>?
        let authorDict : Dictionary<String>?
    }

The error is:

The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))

The non-working code I am using to decode is:

let task = session.dataTask(with: url) { data, response, error in
            if let data = data, error == nil {
                let nsdata = NSData(data: data)
                DispatchQueue.main.async {
                    if let str = String(data: data, encoding: .utf8) {

                        let json = try? JSONSerialization.jsonObject(with: data, options: [])                        
                        do {

                            let mybooks = try JSONDecoder().decode(BooksReturned.self, from: data)
                             //do something with book
                            }

                        } catch {
                            print(error.localizedDescription)
                            print(error)
                        }
                    }
                }
            } else {
                // Failure
            }
        }
        task.resume()
    }

I have some very limited ability to change JSON. The only thing I can do is remove the "books" : Everything else is received from an external API.

Thanks for any suggestions on how to get this to work.

zztop
  • 701
  • 1
  • 7
  • 20
  • The error is saying that you have invalid JSON. Could you print `let res = data.map { String(format: "02hhX", $0) }.joined()`? – Larme Jun 10 '20 at 16:45
  • Good while you are learning the ropes. But when you have lots of json to parse and create models I prefer tools like - https://app.quicktype.io/ Its a fast way to create models, does all the checks for you, and creates models in couple different languages. Try it out once. – SeriousSam Jun 10 '20 at 17:03
  • Wow, just tried app.quicktype.io. Awesome. – zztop Jun 10 '20 at 19:00

1 Answers1

1

The JSON you provided seems to be valid. Modify your Book model and the decoding part as the following.

Model:

struct Book: Codable {
    let title, author: String
}

Decoding:

let task = session.dataTask(with: url) { data, response, error in
    if let data = data, error == nil {
        DispatchQueue.main.async {
            do {
                let mybooks = try JSONDecoder().decode(BooksReturned.self, from: data)
                print(mybooks)
            }
        } catch {
            print(error.localizedDescription)
            print(error)
        }
    }
} else {
    // Failure
}
task.resume()
Frankenstein
  • 15,732
  • 4
  • 22
  • 47
  • am I keeping the BooksReturned struct and getting rid of the BookParts so I have BooksReturned and the new code for Book? – zztop Jun 10 '20 at 16:52
  • Get rid of the `BookParts` and keep the `BookReturned` as given above we're trying to decode `BookReturned`. – Frankenstein Jun 10 '20 at 16:54
  • Follow up question. I was under the impression that [Books] would give me an array of books but when I try to call BooksReturned[0] I get error that Type BooksRetuned has no subscript Members. How would I get first item? – zztop Jun 10 '20 at 18:56
  • I was finally able to reference this with let abook = mybooks?.books?[0] . I guess the actual array is books, not BooksReturned – zztop Jun 10 '20 at 19:33