0

I have a below JSON format which belongs to a shop which inside this json object, Data field is a JSON array consists of a hierarchy of product categories which categories are stored in a nested hierarchical format (Each category have children and each child may have its own children, etc.).

{"Data":[
            {"ID":1,"ParentCategoryId":0,"Name": "Parent1","Children":
                [
                    {"ID":2,"ParentCategoryId":1,"Name": "P1Child1","Children":[]},
                    {"ID":3,"ParentCategoryId":1,"Name": "P1Child2","Children":[]},
                    {"ID":4,"ParentCategoryId":1,"Name": "P1Child3","Children":[]},
                    {"ID":5,"ParentCategoryId":1,"Name": "P1Child4","Children":[]},
                ]
            },
            {"ID":6,"ParentCategoryId":0,"Name": "Parent2","Children":
                [
                    {"ID":7,"ParentCategoryId":6,"Name": "P2Child1","Children":[]},
                    {"ID":8,"ParentCategoryId":6,"Name": "P2Child2","Children":[]},
                    {"ID":9,"ParentCategoryId":6,"Name": "P2Child3","Children":[]}
                ]
            }
        ]
}

Reading this format using Swifty JSON usign json["Data"].array returns a flat list of categories which have no hierarchy. I want to know how can I read this hierarchical JSON object while preserving its structure. Here is current structure of my Model Object (which is not included Children filed but must be modified to be so):

open class ProductCategory: NSObject {


    var idd                 :  NSInteger
    var name                :  String
    var parentCategoryId    :  NSInteger
    ...

}
VSB
  • 9,825
  • 16
  • 72
  • 145

3 Answers3

0

Here's how you could model this using Codable

struct MyData: Codable {
    let data: [Datum]

    enum CodingKeys: String, CodingKey {
        case data = "Data"
    }
}

struct Datum: Codable {
    let id, parentCategoryID: Int
    let name: String
    let children: [Datum]

    enum CodingKeys: String, CodingKey {
        case id = "ID"
        case parentCategoryID = "ParentCategoryId"
        case name = "Name"
        case children = "Children"
    }
}

do {
    let myData = try JSONDecoder().decode(MyData.self, from: yourJsonData)
} catch {
    print(error)
}
Gereon
  • 17,258
  • 4
  • 42
  • 73
  • @VSB What is the issue with this approach? How exactly you want to design your model? – PGDev May 22 '19 at 09:24
  • @PGDev I have no problem with approach. -1 is not mine! But I'm still looking for other possible answers which needs less change in my code base. – VSB May 22 '19 at 10:44
  • @VSB what is your "codebase"? Could you improve/clarify your question so we can better understand what you want from a solution? – Joakim Danielson May 22 '19 at 10:48
  • @JoakimDanielson Responses in my API calls are parsed by Swifty JSON and models are based on this scenario. I don't want to rewrite all my request/responses to make them fit with `Codable` and get rid of Swifty JSON. I don't know if this is a good preference or not since I'm newbie in iOS and Swift however doing such a thing in android environment using Retrofit and GSON is straightforward and is something like what this answer did for `Codable`s. But I want to know is it possible only using Swifty JSON or not. – VSB May 22 '19 at 10:58
  • @JoakimDanielson Please correct me if I'm making mistakes. – VSB May 22 '19 at 10:59
  • @VSB [Edit](https://stackoverflow.com/posts/56252553/edit) your question instead of posting more info in comments – Joakim Danielson May 22 '19 at 11:11
  • 2
    Its better you start using `Codable` instead of a third party library. It is much more efficient and readable. – PGDev May 22 '19 at 11:33
0

If you can consider moving from swiftyjson to JSONSerialization the following should give you the structure you are after

do {
    if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
        if let categories = json["Data"] as? [[String: Any]] {            
          //map data to your classes here
        }
    }
} catch {
    print("Decode failed: \(error)")
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
-1

If you use Codable, you don't need SwiftyJSON, you could just do :

        do {
            let productsData = try JSONDecoder().decode(ProductsDataResponse.self, from: (jsonString.data(using: .utf8))!)
        } catch let e {
            print("Couldn't Parse data because... \(e)")
        }

Where ProductsDataResponse is :

struct ProductsDataResponse: Codable {
    let data: [ProductCategory]

    enum CodingKeys: String, CodingKey {
        case data = "Data"
    }
}
iMahdi
  • 338
  • 2
  • 9