0

I am trying to parse some nested JSON retrieved through an API but am having trouble isolating specific key-value pairs. In fact, I have some confusion over the difference between the JSON data and the dictionary obtained through serialization.

To retrieve the data I am using:

let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {                                                 
                return
            } 

To convert the data to a JSON dictionary, I am doing

do {
                let stringDic = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
            } catch let error {
                print(error)
            }

When printed, this produces nested output of the form:

Optional(["document_tone": {
    "tone_categories" =     (
                {
            "category_id" = "emotion_tone";
            "category_name" = "Emotion Tone";
  and so forth

My question is how can I get a unique value such as that for the key category_name?

If I try to use

let myCat = stringDic["category_name"]

Fix-it requires let document_tone = stringDic?["document_tone"] which if printed to console just prints whole dictionary over again.

Thanks in advance for any suggestions.

1
  • use json decoder with structs Commented Sep 22, 2018 at 16:22

2 Answers 2

4

It's pretty easy: () is array, {} is dictionary and the compiler must know the static types of all subscripted objects:

if let documentTone = stringDic?["document_tone"] as? [String:Any],
   let toneCategories = documentTone["tone_categories"] as? [[String:Any]] {
   for category in toneCategories {
       print(category["category_name"])
   }
}
Sign up to request clarification or add additional context in comments.

2 Comments

What is difference between [String:Any] and [[String:Any]]
Dictionary ([String:Any]) vs. Array ([[String:Any]])
2

I think it's better to use Decodable

struct Root:Decodable {
     let documentTone : InnerItem 
} 
struct InnerItem:Decodable {
     let toneCategories: [BottomItem] 
}  
struct BottomItem:Decodable {
     let categoryId: String
     let categoryName: String 
}

do {
   let decoder = JSONDecoder()
   decoder.keyDecodingStrategy = .convertFromSnakeCase
   let result = try decoder.decode(Root.self, from: data)
   //print all names 
   result.documentTone.toneCategories.forEach {print($0.categoryName) }
} catch {
  print(error)
}

2 Comments

You can omit all CodingKeys if you add the keyDecodingStrategy = .convertFromSnakeCase
@vadian i think it's a good tip here , originally old parsed keys were not like that so i used to use codingKeys which let me drop that optimized way

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.