-1

I have a Json file that lists books sorted in categories.

{
  "FullBookList": [
    {
      "Fantasy": [
        {
          "title": "Alice's Adventures in Wonderland",
          "author": "Lewis Carrol"
        }
      ],
      "Fiction": [
        {
          "Title": "Hamlet",
          "Author": "Maggie O'Farrel"
        }
      ],
      "Comedy": [
        {
          "Title": "Good Omans",
          "Author": "Neil Gaiman"
        }
      ]
    }
  ]
}

I'm trying to make swiftui create a list the "FullBookList' array so it lists...

  1. Fantasy >
  2. Fiction >
  3. Comedy >

Any help? I hope I've explained clearly. import Foundation

struct BookCategory: Decodable {
    let FullBookList: [FullBookList]
}

struct FullBookList: Decodable {
    let Fantasy: [Books]
}

struct Books: Decodable {
    let title: String
    let author: String
}

class BookJson: ObservableObject {

    func GetBookList() {
        do {
            let json = Bundle.main.url(forResource: "Books", withExtension: "json")
            let jsonData = try Data(contentsOf: json!)
            let book = try! JSONDecoder().decode(BookCategory.self, from: jsonData)
            DispatchQueue.main.async {
                print(book.FullBookList) //???
                    }
        } catch {
            print("oof")
        }
    }

}
Sparks
  • 171
  • 9
  • 1
    Please show the code you have so far. – vadian Jun 07 '21 at 12:30
  • Added code to question – Sparks Jun 07 '21 at 13:37
  • Does this answer your question? [Decode JSON from the nested container and check its type dynamically for typecasting in swift](https://stackoverflow.com/questions/67195920/decode-json-from-the-nested-container-and-check-its-type-dynamically-for-typecas) – lorem ipsum Jun 07 '21 at 14:10

1 Answers1

1

First of all change the structure of the JSON to something like this because it's easier to parse

{
    "categories": [
        {
        "name": "Fantasy",
        "books": [
            {
                "title": "Alice's Adventures in Wonderland",
                "author": "Lewis Carrol"
            }
        ]
        },{
        "name": "Fiction",
        "books": [
            {
                 "title": "Hamlet",
                 "author": "Maggie O'Farrel"
            }
        ]
        },{
        "name": "Comedy",
        "books": [
            {
                 "title": "Good Omans",
                 "author": "Neil Gaiman"
            }
        ]
        }
    ]
}

The corresponding structs are

struct BookData: Decodable {
    let categories: [Category]
}

struct Category: Decodable {
    let name : String
    let books: [Book]
}

struct Book: Decodable, Identifiable {
    private enum CodingKeys : String, CodingKey { case title, author }
    
    let id = UUID()
    let title: String
    let author: String
}

In the ObservableObject class add a @Published property which will notify on changes

class BookController : ObservableObject {
    
    @Published var categories = [Category]()

    func loadData() {
        let url = Bundle.main.url(forResource: "Books", withExtension: "json")!
        let data = try! Data(contentsOf: url)
        do {
            let bookData = try JSONDecoder().decode( BookData.self, from: data)
            DispatchQueue.main.async {
                self.categories = bookData.categories
            }
        } catch {
            print(error)
        }
    }
}

In the view load the data onAppear and build the UI

struct ContentView : View {
    @StateObject var bookController = BookController()
    
    var body: some View {
        List {
            ForEach(bookController.categories, id: \.name) { category in
                Section(header: Text(category.name)) {
                    ForEach(category.books) { book in
                        HStack {
                            Text(book.author)
                            Spacer()
                            Text(book.title)
                        }
                    }
                }
           }
        }
        .onAppear() {
            bookController.loadData()
        }
    }
}
vadian
  • 274,689
  • 30
  • 353
  • 361