How to manually parse a nested array from a JSON file into a nested array of a data model?

91 Views Asked by At

I recently started learning Swift and was faced with the next problem. I need to use the Alamofire framework and implement manual data parsing from the JSON file into the data model. In this case, the JSON file has a nested array. I wrote the code, but an error message appears.

What needs to be done to perform such parsing?

This is the JSON file.

["type": product, "number": 10, "offset": 0, "processingTimeMs": 4735, "products": <__NSArrayI 0x600002629e00>(
{
    id = 10026738;
    image = "https://spoonacular.com/productImages/10026738-312x231.jpg";
    imageType = jpg;
    title = "Jenos by totinos crsp n tsty pizza for 1 combo";
},
{
    id = 8215206;
    image = "https://spoonacular.com/productImages/8215206-312x231.jpg";
    imageType = jpg;
    title = "Supreme sausage, pepperoni, green, red and yellow peppers, roasted garlic & red onions brick oven crust pizza, supreme";
},
{
    id = 9822788;
    image = "https://spoonacular.com/productImages/9822788-312x231.jpg";
    imageType = jpg;
    title = "Grisinetos pizza";
},
...

)
, "totalProducts": 16410]

This is the data model.

struct Product: Decodable {
    let id: Int
    let title: String
    let imageType: String
}

struct Grocery: Decodable {
    let products: [Product]
    let totalProducts: Int
    let type: String
    let offset: Int
    let number: Int
}

This is the function I wrote

private func fetchProducts() {
    AF.request(groceryLink)
        .validate()
        .responseJSON { dataResponse in
        switch dataResponse.result {
        case .success(let value):
            guard let groceryDetails = value as? [String: Any] else { return }
            
            var products: [Product] = []
            
            for productDetails in groceryDetails["products"] {
                let product = Product(
                    id: productDetails["id"] as? Int ?? 0,
                    title: productDetails["title"] as? String ?? "",
                    imageType: productDetails["imageType"] as? String ?? ""
                )
                products.append(product)
            }

            let grocery = Grocery(products: products,
                                  totalProducts: groceryDetails["totalProducts"] as? Int ?? 0,
                                  type: groceryDetails["type"] as? String ?? "",
                                  offset: groceryDetails["offset"] as? Int ?? 0,
                                  number: groceryDetails["number"] as? Int ?? 0)
            
        case .failure(let error):
            print(error)
        }
    }
}
1

There are 1 best solutions below

0
maxMas On

I found a solution to this task.

In the first line of the loop, it was necessary to cast the received data to an array of dictionaries [[String: Any]]

The fixed code is here:

private func fetchProducts() {
    AF.request(groceryLink)
        .validate()
        .responseJSON { dataResponse in
        switch dataResponse.result {
        case .success(let value):
            guard let groceryDetails = value as? [String: Any] else { return }
            
            var products: [Product] = []
            
            for productDetails in groceryDetails["products"] as? [[String: Any]] ?? [] {
                let product = Product(
                    id: productDetails["id"] as? Int ?? 0,
                    title: productDetails["title"] as? String ?? "",
                    imageType: productDetails["imageType"] as? String ?? ""
                )
                products.append(product)
            }

            let grocery = Grocery(products: products,
                                  totalProducts: groceryDetails["totalProducts"] as? Int ?? 0,
                                  type: groceryDetails["type"] as? String ?? "",
                                  offset: groceryDetails["offset"] as? Int ?? 0,
                                  number: groceryDetails["number"] as? Int ?? 0)
            
        case .failure(let error):
            print(error)
        }
    }
}