Home > Net >  Loop over object array in Swift
Loop over object array in Swift

Time:10-18

I am trying to create a request object that allows me to use multiple different dynamic objects based on an API call. I currently have the following.

let json = """
{
    "object": "bottle",
    "has_more": false,
    "data": [
        {
          "id": "5ffa81e7-1d91-43b5-83cc-9ee1ab634c7b",
          "name": "14 Hands Hot to Trot White Blend",
          "price": "$8.99",
          "image": "https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/8186/10996/14-Hands-Hot-to-Trot-White-Blend__56901.1488985626.jpg?c=2",
          "sku": "088586004490",
          "size": "750ML",
          "origination": "USA, Washington",
          "varietal": "White Wine",
          "information": "14 Hands Hot to Trot White Blend",
          "proof": 121.5,
          "brand_id": "1",
          "rating": 1,
          "review_count": 5
        }
    ]
}
"""

enum RequestData {
    case bottle([Bottle])
}

enum ObjectType: String, Decodable {
    case bottle
}

struct Request: Decodable {
    let object: ObjectType
    let hasMore: Bool
    let data: RequestData
    
    enum CodingKeys: String, CodingKey { case hasMore = "has_more", object, data}
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.object = try container.decode(ObjectType.self, forKey: .object)
        self.hasMore = try container.decode(Bool.self, forKey: .hasMore)
        switch object {
            case .bottle:
                let bottleData = try container.decode([Bottle].self, forKey: .data)
                data = RequestData.bottle(bottleData)
        }
    }
}

struct Bottle: Decodable {
    let id: String
    let name: String
    let price: String
    let image: String
    let sku: String
    let size: String
    let origination: String
    let varietal: String
    let information: String
    let proof: Float
    let brand_id: String
    let rating: Int
    let review_count: Int
}

let decoder = JSONDecoder()
let requestData = try decoder.decode(Request.self, from: Data(json .utf8))
print(requestData)

It is working as expected, however, I am just not entirely sure how I can access the struct attributes. If I run the above, I get the following output.

Request(object: __lldb_expr_217.ObjectType.bottle, hasMore: false, data: __lldb_expr_217.RequestData.bottle([__lldb_expr_217.Bottle(id: "5ffa81e7-1d91-43b5-83cc-9ee1ab634c7b", name: "14 Hands Hot to Trot White Blend", price: "$8.99", image: "https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/8186/10996/14-Hands-Hot-to-Trot-White-Blend__56901.1488985626.jpg?c=2", sku: "088586004490", size: "750ML", origination: "USA, Washington", varietal: "White Wine", information: "14 Hands Hot to Trot White Blend", proof: 121.5, brand_id: "1", rating: 1, review_count: 5)]))

My goal here is to loop over this Request object and take the name from each Bottle id within that Request object. How can I achieve this? It seems simple I just can't get it to work.

CodePudding user response:

Lets say you add a new bottle to the list to have two bottle in result

      {
         "id":"5ffa81e7-1d91-43b5-83cc-9ee1ab634c8b",
         "name":"New Bottle",
         "price":"$7.99",
         "image":"https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/8186/10996/14-Hands-Hot-to-Trot-White-Blend__56901.1488985626.jpg?c=2",
         "sku":"088586004491",
         "size":"750ML",
         "origination":"USA, Washington",
         "varietal":"White Wine",
         "information":"14 Hands Hot to Trot White Blend",
         "proof":121.5,
         "brand_id":"1",
         "rating":1,
         "review_count":5
      }

you can switch over which enum is the result by doing

switch requestData.data {
case .bottle(let bottleList):
    for bottle in bottleList {
        print(bottle)
    }
}

This will give output:

Bottle(id: "5ffa81e7-1d91-43b5-83cc-9ee1ab634c7b", name: "14 Hands Hot to Trot White Blend", price: "$8.99", image: "https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/8186/10996/14-Hands-Hot-to-Trot-White-Blend__56901.1488985626.jpg?c=2", sku: "088586004490", size: "750ML", origination: "USA, Washington", varietal: "White Wine", information: "14 Hands Hot to Trot White Blend", proof: 121.5, brand_id: "1", rating: 1, review_count: 5)
Bottle(id: "5ffa81e7-1d91-43b5-83cc-9ee1ab634c8b", name: "New Bottle", price: "$7.99", image: "https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/8186/10996/14-Hands-Hot-to-Trot-White-Blend__56901.1488985626.jpg?c=2", sku: "088586004491", size: "750ML", origination: "USA, Washington", varietal: "White Wine", information: "14 Hands Hot to Trot White Blend", proof: 121.5, brand_id: "1", rating: 1, review_count: 5)

What happen if we decide to add more type?

Lets say you add Pillow to object type

struct Pillow: Decodable {
    let id: String
}

enum RequestData {
    case bottle([Bottle])
    case pillow([Pillow])
}

enum ObjectType: String, Decodable {
    case bottle, pillow
}

Now you can just add more case to the print

switch requestData.data {
case .bottle(let bottleList):
    for bottle in bottleList {
        print(bottle)
    }
case .pillow(let pillowList):
    for pillow in pillowList {
        print(pillow)
    }
}
  • Related