How can I parse this JSON Pokemon Dictionary? Pokemon API (swift 3)












1















I have an issue with parsing JSON data from new version of the Pokemon API, specifically with values of the "name" in "type" key.



Json looks like this:



"types": [
{
"slot": 2,
"type": {
"name": "poison",
"url": "https://pokeapi.co/api/v2/type/4/"
}
},
{
"slot": 1,
"type": {
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
}
}
],
"weight": 69


After parsing in Alamofire i'm got the next solution:



if let types = dict["types"] as? [Dictionary<String, String>] , types.count > 0 {

if let type = types[0]["type"] as? Dictionary<String, String> {

if let name = type["name"] {
self._type = name.capitalized
}
}

print("TypeAA: (self._type)")

} else {

self._type = ""
}


And this line also not be executed.
print("TypeAA: (self._type)")
Please advise, how can I parse and get the value of "name" in key named is "type" correctly?










share|improve this question

























  • It is much easier to use Decodable instead of manually parsing the response.

    – Kamran
    Nov 25 '18 at 6:22













  • Thank @Kamran, but pls advise on these code.

    – vaart12345
    Nov 25 '18 at 6:24
















1















I have an issue with parsing JSON data from new version of the Pokemon API, specifically with values of the "name" in "type" key.



Json looks like this:



"types": [
{
"slot": 2,
"type": {
"name": "poison",
"url": "https://pokeapi.co/api/v2/type/4/"
}
},
{
"slot": 1,
"type": {
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
}
}
],
"weight": 69


After parsing in Alamofire i'm got the next solution:



if let types = dict["types"] as? [Dictionary<String, String>] , types.count > 0 {

if let type = types[0]["type"] as? Dictionary<String, String> {

if let name = type["name"] {
self._type = name.capitalized
}
}

print("TypeAA: (self._type)")

} else {

self._type = ""
}


And this line also not be executed.
print("TypeAA: (self._type)")
Please advise, how can I parse and get the value of "name" in key named is "type" correctly?










share|improve this question

























  • It is much easier to use Decodable instead of manually parsing the response.

    – Kamran
    Nov 25 '18 at 6:22













  • Thank @Kamran, but pls advise on these code.

    – vaart12345
    Nov 25 '18 at 6:24














1












1








1








I have an issue with parsing JSON data from new version of the Pokemon API, specifically with values of the "name" in "type" key.



Json looks like this:



"types": [
{
"slot": 2,
"type": {
"name": "poison",
"url": "https://pokeapi.co/api/v2/type/4/"
}
},
{
"slot": 1,
"type": {
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
}
}
],
"weight": 69


After parsing in Alamofire i'm got the next solution:



if let types = dict["types"] as? [Dictionary<String, String>] , types.count > 0 {

if let type = types[0]["type"] as? Dictionary<String, String> {

if let name = type["name"] {
self._type = name.capitalized
}
}

print("TypeAA: (self._type)")

} else {

self._type = ""
}


And this line also not be executed.
print("TypeAA: (self._type)")
Please advise, how can I parse and get the value of "name" in key named is "type" correctly?










share|improve this question
















I have an issue with parsing JSON data from new version of the Pokemon API, specifically with values of the "name" in "type" key.



Json looks like this:



"types": [
{
"slot": 2,
"type": {
"name": "poison",
"url": "https://pokeapi.co/api/v2/type/4/"
}
},
{
"slot": 1,
"type": {
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
}
}
],
"weight": 69


After parsing in Alamofire i'm got the next solution:



if let types = dict["types"] as? [Dictionary<String, String>] , types.count > 0 {

if let type = types[0]["type"] as? Dictionary<String, String> {

if let name = type["name"] {
self._type = name.capitalized
}
}

print("TypeAA: (self._type)")

} else {

self._type = ""
}


And this line also not be executed.
print("TypeAA: (self._type)")
Please advise, how can I parse and get the value of "name" in key named is "type" correctly?







ios json swift parsing






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 25 '18 at 13:15









Peter Brockmann

2,25711924




2,25711924










asked Nov 25 '18 at 5:36









vaart12345vaart12345

163




163













  • It is much easier to use Decodable instead of manually parsing the response.

    – Kamran
    Nov 25 '18 at 6:22













  • Thank @Kamran, but pls advise on these code.

    – vaart12345
    Nov 25 '18 at 6:24



















  • It is much easier to use Decodable instead of manually parsing the response.

    – Kamran
    Nov 25 '18 at 6:22













  • Thank @Kamran, but pls advise on these code.

    – vaart12345
    Nov 25 '18 at 6:24

















It is much easier to use Decodable instead of manually parsing the response.

– Kamran
Nov 25 '18 at 6:22







It is much easier to use Decodable instead of manually parsing the response.

– Kamran
Nov 25 '18 at 6:22















Thank @Kamran, but pls advise on these code.

– vaart12345
Nov 25 '18 at 6:24





Thank @Kamran, but pls advise on these code.

– vaart12345
Nov 25 '18 at 6:24












4 Answers
4






active

oldest

votes


















1














You can't do dict["types"] as? [Dictionary<String, String>] because an item in types can't be cast to Dictionary<String, String>. item has integers like "slot": 2 and dictionaries "type": {...}. So it must be cast to [String : Any] first.



if let types = dict["types"] as? [Any], types.count > 0 {
if let firstObject = (types.first as? [String : Any]),
let type = firstObject["type"] as? [String : String],
let name = type["name"] {
self._type = name.capitalized
}
}


if you want name of each item, you have to loop through the items array.






share|improve this answer


























  • Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

    – vadian
    Nov 25 '18 at 8:38





















0














Or try something similar like this here:



if let types = dict["types"] as? [Any] {
guard types.count > 0 else {
return
}

for elment in types {
if let type = elment["type"] as? [String:Any] {
let name = type["name"] as! String
// Do what you want with it here
}
}
}





share|improve this answer































    0














    You can use AlamofireObjectMapper to parse the JSON response from Alamofire very easily.



    class PokemonTypesResponse: Mappable {
    var types:[Types]?
    var weight:Int?

    required init?(map: Map){

    }

    func mapping(map: Map) {
    types <- map["types"]
    weight <- map["weight"]
    }
    }

    class Types: Mappable {
    var slot:Int?
    var name:String?
    var url:String?

    required init?(map: Map){

    }

    func mapping(map: Map) {
    slot <- map["slot"]
    type <- map["type.name"]
    url <- mapp["type.url"]
    }
    }


    Perform the request with alamofire and use



    .responseArray { (response: DataResponse<[PokemonTypesResponse]>) in
    switch response.result {
    case .success:
    //this is the response as PokemonTypesResponse
    response.result.value
    case .failure(let error):
    print(error)
    }


    to map the JSON result
    I haven't tested it, I wrote it based on my experience.
    I hope it works and it's easy to understand.






    share|improve this answer
























    • Thank all for your answers, my issue now be solved.

      – vaart12345
      Nov 25 '18 at 10:08



















    0














    Your code doesn't work because the first conditional downcast fails.



    The value for key types is [Dictionary<String, Any>] (note the nested dictionary in the JSON) and not [Dictionary<String, String>].



    So basically this works



     if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 {
    if let type = types[0]["type"] as? Dictionary<String, String> {
    if let name = type["name"] {
    self._type = name.capitalized
    }
    }
    print("TypeAA: (self._type)")
    } else {
    self._type = ""
    }


    But the pyramid of doom is cumbersome and never check for an empty array with .count > 0 so this is more efficient



     if let types = dict["types"] as? [Dictionary<String, Any>], 
    let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
    let name = typeInfo["name"] {
    self._type = name.capitalized
    print("TypeAA:", self._type)
    } else {
    self._type = ""
    }


    If you need to consider all names you have to use a loop



     if let types = dict["types"] as? [Dictionary<String, Any>] {
    for type in types {
    if let typeInfo = type["type"] as? Dictionary<String, String>,
    let name = typeInfo["name"] {
    print("TypeAA:", name)
    }
    }
    } else {
    self._type = ""
    }


    If you want to print all names comma separated use



    if let types = dict["types"] as? [Dictionary<String, Any>] {
    let names = types.compactMap { type -> String? in
    guard let typeInfo = type["type"] as? Dictionary<String, String>,
    let name = typeInfo["name"] else { return nil }
    return name
    }
    print(names.joined(separator: ", "))
    }





    share|improve this answer


























    • #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

      – vaart12345
      Nov 25 '18 at 10:07











    • sorry, i am still confuse.

      – vaart12345
      Nov 25 '18 at 11:21











    • sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

      – vaart12345
      Nov 25 '18 at 11:34













    • There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

      – vadian
      Nov 25 '18 at 11:39











    • Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

      – vaart12345
      Nov 25 '18 at 14:41











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464948%2fhow-can-i-parse-this-json-pokemon-dictionary-pokemon-api-swift-3%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You can't do dict["types"] as? [Dictionary<String, String>] because an item in types can't be cast to Dictionary<String, String>. item has integers like "slot": 2 and dictionaries "type": {...}. So it must be cast to [String : Any] first.



    if let types = dict["types"] as? [Any], types.count > 0 {
    if let firstObject = (types.first as? [String : Any]),
    let type = firstObject["type"] as? [String : String],
    let name = type["name"] {
    self._type = name.capitalized
    }
    }


    if you want name of each item, you have to loop through the items array.






    share|improve this answer


























    • Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

      – vadian
      Nov 25 '18 at 8:38


















    1














    You can't do dict["types"] as? [Dictionary<String, String>] because an item in types can't be cast to Dictionary<String, String>. item has integers like "slot": 2 and dictionaries "type": {...}. So it must be cast to [String : Any] first.



    if let types = dict["types"] as? [Any], types.count > 0 {
    if let firstObject = (types.first as? [String : Any]),
    let type = firstObject["type"] as? [String : String],
    let name = type["name"] {
    self._type = name.capitalized
    }
    }


    if you want name of each item, you have to loop through the items array.






    share|improve this answer


























    • Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

      – vadian
      Nov 25 '18 at 8:38
















    1












    1








    1







    You can't do dict["types"] as? [Dictionary<String, String>] because an item in types can't be cast to Dictionary<String, String>. item has integers like "slot": 2 and dictionaries "type": {...}. So it must be cast to [String : Any] first.



    if let types = dict["types"] as? [Any], types.count > 0 {
    if let firstObject = (types.first as? [String : Any]),
    let type = firstObject["type"] as? [String : String],
    let name = type["name"] {
    self._type = name.capitalized
    }
    }


    if you want name of each item, you have to loop through the items array.






    share|improve this answer















    You can't do dict["types"] as? [Dictionary<String, String>] because an item in types can't be cast to Dictionary<String, String>. item has integers like "slot": 2 and dictionaries "type": {...}. So it must be cast to [String : Any] first.



    if let types = dict["types"] as? [Any], types.count > 0 {
    if let firstObject = (types.first as? [String : Any]),
    let type = firstObject["type"] as? [String : String],
    let name = type["name"] {
    self._type = name.capitalized
    }
    }


    if you want name of each item, you have to loop through the items array.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 25 '18 at 8:43

























    answered Nov 25 '18 at 6:26









    BilalBilal

    9,94952843




    9,94952843













    • Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

      – vadian
      Nov 25 '18 at 8:38





















    • Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

      – vadian
      Nov 25 '18 at 8:38



















    Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

    – vadian
    Nov 25 '18 at 8:38







    Your solution works but your statement is wrong. [Dictionary<String, String>] is an array of dictionaries, too. And if you check first the check for empty is redundant.

    – vadian
    Nov 25 '18 at 8:38















    0














    Or try something similar like this here:



    if let types = dict["types"] as? [Any] {
    guard types.count > 0 else {
    return
    }

    for elment in types {
    if let type = elment["type"] as? [String:Any] {
    let name = type["name"] as! String
    // Do what you want with it here
    }
    }
    }





    share|improve this answer




























      0














      Or try something similar like this here:



      if let types = dict["types"] as? [Any] {
      guard types.count > 0 else {
      return
      }

      for elment in types {
      if let type = elment["type"] as? [String:Any] {
      let name = type["name"] as! String
      // Do what you want with it here
      }
      }
      }





      share|improve this answer


























        0












        0








        0







        Or try something similar like this here:



        if let types = dict["types"] as? [Any] {
        guard types.count > 0 else {
        return
        }

        for elment in types {
        if let type = elment["type"] as? [String:Any] {
        let name = type["name"] as! String
        // Do what you want with it here
        }
        }
        }





        share|improve this answer













        Or try something similar like this here:



        if let types = dict["types"] as? [Any] {
        guard types.count > 0 else {
        return
        }

        for elment in types {
        if let type = elment["type"] as? [String:Any] {
        let name = type["name"] as! String
        // Do what you want with it here
        }
        }
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 25 '18 at 7:18









        Mattk90Mattk90

        5541615




        5541615























            0














            You can use AlamofireObjectMapper to parse the JSON response from Alamofire very easily.



            class PokemonTypesResponse: Mappable {
            var types:[Types]?
            var weight:Int?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            types <- map["types"]
            weight <- map["weight"]
            }
            }

            class Types: Mappable {
            var slot:Int?
            var name:String?
            var url:String?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            slot <- map["slot"]
            type <- map["type.name"]
            url <- mapp["type.url"]
            }
            }


            Perform the request with alamofire and use



            .responseArray { (response: DataResponse<[PokemonTypesResponse]>) in
            switch response.result {
            case .success:
            //this is the response as PokemonTypesResponse
            response.result.value
            case .failure(let error):
            print(error)
            }


            to map the JSON result
            I haven't tested it, I wrote it based on my experience.
            I hope it works and it's easy to understand.






            share|improve this answer
























            • Thank all for your answers, my issue now be solved.

              – vaart12345
              Nov 25 '18 at 10:08
















            0














            You can use AlamofireObjectMapper to parse the JSON response from Alamofire very easily.



            class PokemonTypesResponse: Mappable {
            var types:[Types]?
            var weight:Int?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            types <- map["types"]
            weight <- map["weight"]
            }
            }

            class Types: Mappable {
            var slot:Int?
            var name:String?
            var url:String?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            slot <- map["slot"]
            type <- map["type.name"]
            url <- mapp["type.url"]
            }
            }


            Perform the request with alamofire and use



            .responseArray { (response: DataResponse<[PokemonTypesResponse]>) in
            switch response.result {
            case .success:
            //this is the response as PokemonTypesResponse
            response.result.value
            case .failure(let error):
            print(error)
            }


            to map the JSON result
            I haven't tested it, I wrote it based on my experience.
            I hope it works and it's easy to understand.






            share|improve this answer
























            • Thank all for your answers, my issue now be solved.

              – vaart12345
              Nov 25 '18 at 10:08














            0












            0








            0







            You can use AlamofireObjectMapper to parse the JSON response from Alamofire very easily.



            class PokemonTypesResponse: Mappable {
            var types:[Types]?
            var weight:Int?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            types <- map["types"]
            weight <- map["weight"]
            }
            }

            class Types: Mappable {
            var slot:Int?
            var name:String?
            var url:String?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            slot <- map["slot"]
            type <- map["type.name"]
            url <- mapp["type.url"]
            }
            }


            Perform the request with alamofire and use



            .responseArray { (response: DataResponse<[PokemonTypesResponse]>) in
            switch response.result {
            case .success:
            //this is the response as PokemonTypesResponse
            response.result.value
            case .failure(let error):
            print(error)
            }


            to map the JSON result
            I haven't tested it, I wrote it based on my experience.
            I hope it works and it's easy to understand.






            share|improve this answer













            You can use AlamofireObjectMapper to parse the JSON response from Alamofire very easily.



            class PokemonTypesResponse: Mappable {
            var types:[Types]?
            var weight:Int?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            types <- map["types"]
            weight <- map["weight"]
            }
            }

            class Types: Mappable {
            var slot:Int?
            var name:String?
            var url:String?

            required init?(map: Map){

            }

            func mapping(map: Map) {
            slot <- map["slot"]
            type <- map["type.name"]
            url <- mapp["type.url"]
            }
            }


            Perform the request with alamofire and use



            .responseArray { (response: DataResponse<[PokemonTypesResponse]>) in
            switch response.result {
            case .success:
            //this is the response as PokemonTypesResponse
            response.result.value
            case .failure(let error):
            print(error)
            }


            to map the JSON result
            I haven't tested it, I wrote it based on my experience.
            I hope it works and it's easy to understand.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 25 '18 at 8:21









            Dimitrios KalaitzidisDimitrios Kalaitzidis

            19219




            19219













            • Thank all for your answers, my issue now be solved.

              – vaart12345
              Nov 25 '18 at 10:08



















            • Thank all for your answers, my issue now be solved.

              – vaart12345
              Nov 25 '18 at 10:08

















            Thank all for your answers, my issue now be solved.

            – vaart12345
            Nov 25 '18 at 10:08





            Thank all for your answers, my issue now be solved.

            – vaart12345
            Nov 25 '18 at 10:08











            0














            Your code doesn't work because the first conditional downcast fails.



            The value for key types is [Dictionary<String, Any>] (note the nested dictionary in the JSON) and not [Dictionary<String, String>].



            So basically this works



             if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 {
            if let type = types[0]["type"] as? Dictionary<String, String> {
            if let name = type["name"] {
            self._type = name.capitalized
            }
            }
            print("TypeAA: (self._type)")
            } else {
            self._type = ""
            }


            But the pyramid of doom is cumbersome and never check for an empty array with .count > 0 so this is more efficient



             if let types = dict["types"] as? [Dictionary<String, Any>], 
            let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            self._type = name.capitalized
            print("TypeAA:", self._type)
            } else {
            self._type = ""
            }


            If you need to consider all names you have to use a loop



             if let types = dict["types"] as? [Dictionary<String, Any>] {
            for type in types {
            if let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            print("TypeAA:", name)
            }
            }
            } else {
            self._type = ""
            }


            If you want to print all names comma separated use



            if let types = dict["types"] as? [Dictionary<String, Any>] {
            let names = types.compactMap { type -> String? in
            guard let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] else { return nil }
            return name
            }
            print(names.joined(separator: ", "))
            }





            share|improve this answer


























            • #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

              – vaart12345
              Nov 25 '18 at 10:07











            • sorry, i am still confuse.

              – vaart12345
              Nov 25 '18 at 11:21











            • sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

              – vaart12345
              Nov 25 '18 at 11:34













            • There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

              – vadian
              Nov 25 '18 at 11:39











            • Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

              – vaart12345
              Nov 25 '18 at 14:41
















            0














            Your code doesn't work because the first conditional downcast fails.



            The value for key types is [Dictionary<String, Any>] (note the nested dictionary in the JSON) and not [Dictionary<String, String>].



            So basically this works



             if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 {
            if let type = types[0]["type"] as? Dictionary<String, String> {
            if let name = type["name"] {
            self._type = name.capitalized
            }
            }
            print("TypeAA: (self._type)")
            } else {
            self._type = ""
            }


            But the pyramid of doom is cumbersome and never check for an empty array with .count > 0 so this is more efficient



             if let types = dict["types"] as? [Dictionary<String, Any>], 
            let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            self._type = name.capitalized
            print("TypeAA:", self._type)
            } else {
            self._type = ""
            }


            If you need to consider all names you have to use a loop



             if let types = dict["types"] as? [Dictionary<String, Any>] {
            for type in types {
            if let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            print("TypeAA:", name)
            }
            }
            } else {
            self._type = ""
            }


            If you want to print all names comma separated use



            if let types = dict["types"] as? [Dictionary<String, Any>] {
            let names = types.compactMap { type -> String? in
            guard let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] else { return nil }
            return name
            }
            print(names.joined(separator: ", "))
            }





            share|improve this answer


























            • #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

              – vaart12345
              Nov 25 '18 at 10:07











            • sorry, i am still confuse.

              – vaart12345
              Nov 25 '18 at 11:21











            • sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

              – vaart12345
              Nov 25 '18 at 11:34













            • There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

              – vadian
              Nov 25 '18 at 11:39











            • Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

              – vaart12345
              Nov 25 '18 at 14:41














            0












            0








            0







            Your code doesn't work because the first conditional downcast fails.



            The value for key types is [Dictionary<String, Any>] (note the nested dictionary in the JSON) and not [Dictionary<String, String>].



            So basically this works



             if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 {
            if let type = types[0]["type"] as? Dictionary<String, String> {
            if let name = type["name"] {
            self._type = name.capitalized
            }
            }
            print("TypeAA: (self._type)")
            } else {
            self._type = ""
            }


            But the pyramid of doom is cumbersome and never check for an empty array with .count > 0 so this is more efficient



             if let types = dict["types"] as? [Dictionary<String, Any>], 
            let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            self._type = name.capitalized
            print("TypeAA:", self._type)
            } else {
            self._type = ""
            }


            If you need to consider all names you have to use a loop



             if let types = dict["types"] as? [Dictionary<String, Any>] {
            for type in types {
            if let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            print("TypeAA:", name)
            }
            }
            } else {
            self._type = ""
            }


            If you want to print all names comma separated use



            if let types = dict["types"] as? [Dictionary<String, Any>] {
            let names = types.compactMap { type -> String? in
            guard let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] else { return nil }
            return name
            }
            print(names.joined(separator: ", "))
            }





            share|improve this answer















            Your code doesn't work because the first conditional downcast fails.



            The value for key types is [Dictionary<String, Any>] (note the nested dictionary in the JSON) and not [Dictionary<String, String>].



            So basically this works



             if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 {
            if let type = types[0]["type"] as? Dictionary<String, String> {
            if let name = type["name"] {
            self._type = name.capitalized
            }
            }
            print("TypeAA: (self._type)")
            } else {
            self._type = ""
            }


            But the pyramid of doom is cumbersome and never check for an empty array with .count > 0 so this is more efficient



             if let types = dict["types"] as? [Dictionary<String, Any>], 
            let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            self._type = name.capitalized
            print("TypeAA:", self._type)
            } else {
            self._type = ""
            }


            If you need to consider all names you have to use a loop



             if let types = dict["types"] as? [Dictionary<String, Any>] {
            for type in types {
            if let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] {
            print("TypeAA:", name)
            }
            }
            } else {
            self._type = ""
            }


            If you want to print all names comma separated use



            if let types = dict["types"] as? [Dictionary<String, Any>] {
            let names = types.compactMap { type -> String? in
            guard let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] else { return nil }
            return name
            }
            print(names.joined(separator: ", "))
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 25 '18 at 17:54

























            answered Nov 25 '18 at 8:37









            vadianvadian

            146k13157175




            146k13157175













            • #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

              – vaart12345
              Nov 25 '18 at 10:07











            • sorry, i am still confuse.

              – vaart12345
              Nov 25 '18 at 11:21











            • sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

              – vaart12345
              Nov 25 '18 at 11:34













            • There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

              – vadian
              Nov 25 '18 at 11:39











            • Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

              – vaart12345
              Nov 25 '18 at 14:41



















            • #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

              – vaart12345
              Nov 25 '18 at 10:07











            • sorry, i am still confuse.

              – vaart12345
              Nov 25 '18 at 11:21











            • sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

              – vaart12345
              Nov 25 '18 at 11:34













            • There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

              – vadian
              Nov 25 '18 at 11:39











            • Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

              – vaart12345
              Nov 25 '18 at 14:41

















            #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

            – vaart12345
            Nov 25 '18 at 10:07





            #Vadian, your solution is easy to understand and it works. It is very helpful to me. Thank you so much.

            – vaart12345
            Nov 25 '18 at 10:07













            sorry, i am still confuse.

            – vaart12345
            Nov 25 '18 at 11:21





            sorry, i am still confuse.

            – vaart12345
            Nov 25 '18 at 11:21













            sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

            – vaart12345
            Nov 25 '18 at 11:34







            sorry, i am still confuse. i use your loop code, but it seem only one type is being got correctly. The console log is like below.</br> TypeAA: poison TypeAA: bug </br>Did arrive here? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC Read Status [1:0x0]: 1:57 </br> And my expected is print out: "Poison/Grass" (2 types), how to perform?

            – vaart12345
            Nov 25 '18 at 11:34















            There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

            – vadian
            Nov 25 '18 at 11:39





            There is no string bug in the given JSON. And TypeAA: poison / TypeAA: bug are 2 types. Each type is printed separately.

            – vadian
            Nov 25 '18 at 11:39













            Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

            – vaart12345
            Nov 25 '18 at 14:41





            Thnks @vadian, one more question, when using your loop code, how to print out the string like this: "Poison/Grass". I am a newbie, pls advice.

            – vaart12345
            Nov 25 '18 at 14:41


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53464948%2fhow-can-i-parse-this-json-pokemon-dictionary-pokemon-api-swift-3%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown