Swift
Swift

Reputation: 1182

Unable to get value from JSON array of dictionaries in swift

json response: "result": {

   "user_images": [
        {
            "id": 113,
            "user_id": "160",
            "image": "1617349564.jpg",
            "image_title": "33"
          
        },
        {
            "id": 112,
            "user_id": "160",
            "image": "1617349541.jpg",
            "image_title": "22"
           
        },
        {
            "id": 111,
            "user_id": "160",
            "image": "1617349528.jpg",
            "image_title": "11"
        },
        ........

code: with this code i am getting response like above means all user_images array coming... but here i need image_title how to get that.. if i run for loop getting error.. pls do help

  if let code = ((response.dict?["result"] as? [String : Any])){
      let userImages = code["user_images"] as? [String : Any]

   }

how to get image_title value from above array of dictionaries

Upvotes: 0

Views: 1191

Answers (2)

xTwisteDx
xTwisteDx

Reputation: 2472

Code from @Sh_Khan

if let code = response.dict?["result"] as? [String : Any]  {
  //You're using "as?" which means you're casting as an optional type. 
  //One simple solution to this is here where it's unwrapped using "if let"
  if let userImages = code["user_images"] as? [[String : Any]] {
      // [String:Any] is a Dictionary
      // [[String:Any]] is an Array of Dictionary
      for item in userImages {
         print(item["image_title"])
      } 
   } else {
      // We didn't unwrap this safely at all, do something else. 
}

Let's dive into this a little bit. This structure is a JSON Object

    {
        "id": 113,
        "user_id": "160",
        "image": "1617349564.jpg",
        "image_title": "33"
    }

But it's only a JSON object when it stands alone. Adding a key, or in this example user_images makes it a dictionary. Notice that the [ is not wrapped around it. Meaning it's a standalone dictionary. If this was your object, and this alone, your original code would work, but you're dealing with an Array of Dictionaries.

"user_images":
    {
        "id": 113,
        "user_id": "160",
        "image": "1617349564.jpg",
        "image_title": "33"
    }

This line of code essentially means that you're expecting to get back that Array of Dictionary. Bear in mind, each value for the dictionary is not an array value, which is why you don't see something like this [[[String: Any]]] because the data isn't nested like that.

if let userImages = code["user_images"] as? [[String : Any]]

What's this about optionals?

An optional is basically a nil possible value that can be returned. Typically when working with JSON you cannot guarantee that you'll always receive a value for a given key. It's even possible for a key value pair to be completely missing. If that were to happen you'd end up with a crash, because it's not handled. Here are the most common ways to handle Optionals

var someString: String? //This is the optional one
var someOtherString = "Hello, World!" //Non-optional

if let unwrappedString1 = someString {
   //This code will never be reached
} else {
   //This code will, because it can't be unwrapped.
}

guard let unwrappedString2 = someString else {
   //This code block will run
   return //Could also be continue, break, or return someValue
} 

//The code will never make it here.
print(someOtherString)

Furthermore, you can work with optionals by chain unwrapping them which is a nifty feature.

var someString: String?
var someInt: Int?
var someBool: Bool?

someString = "Hello, World!"

//someString is not nil, but an important distinction to make, if any
//fail, ALL fail.
if let safeString = someString,
   let safeInt = someInt,
   let safeBool = someBool {
      //If the values are unwrapped safely, they will be accessible here.
      //In this case, they are nil, so this block will never be hit.
      //I make this point because of scope, the guard statement saves you from the 
      //scoping issue present in if let unwrapping.
      print(safeString)
      print(safeInt)
      print(safeBool)
}

guard let safeString = someString,
      let safeInt = someInt, 
      let safeBool = someBool {
         //This will be hit if a value is null
      return
}

//However notice the scope is available outside of the guard statement, 
//meaning you can safely use the values now without them being contained
//to an if statement. Despite this example, they would never be hit.
print(safeString)
print(safeInt)
print(safeBool)

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100541

Sol 1

if let code = response.dict?["result"] as? [String : Any]  {
  if let userImages = code["user_images"] as? [[String : Any]] {
      for item in userImages {
         print(item["image_title"])
      } 
   } 
}

Sol 2

if let code = response.dict?["result"] as? [String : Any]  { 
   do { 
       let data = try JSONSerialization.data(withJSONObject: code) 
       let decoder = JSONDecoder() 
       decoder.keyDecodingStrategy = .convertFromSnakeCase 
       let res = try decoder.decode(Result.self, from: data) 
       let titles = res.userImages.map { $0.imageTitle } 
       print(titles) 
   }
   catch {
       print(error)
   } 
}

// MARK: - Result
struct Result: Codable {
    let userImages: [UserImage]
 
} 
// MARK: - UserImage
struct UserImage: Codable {
    let id: Int
    let userId, image, imageTitle: String
}

Upvotes: 2

Related Questions