PruitIgoe
PruitIgoe

Reputation: 6384

Swift 3: Trying to parse JSON but keep getting type issues

I'm converting from Obj-c to Swift and at times it can be quite frustrating as simple task I can do in Obj-C in minutes eat up hours. I know it's part of the process of learning but grrrr all the same.

I built a test app to query iTunes with a song name and return all the results. But for the life of me I can't seem to parse the return to the individual dictionary level.

I can use this code to mine down to the level where I think I have an array of dictionaries:

 if let dictData = dictJSON["Data"] as? [String:Any],  let arrResults = dictData["results"] as? Array<Any> {

I can then iterate through that array like so:

for i in 1...arrResults.count {

or

for dictThisSong in arrResults { 

in either case I get results like so:

{
    artistId = 158038;
    artistName = "Fleetwood Mac";
    artistViewUrl = "https://itunes.apple.com/us/artist/fleetwood-mac/id158038?uo=4";
    artworkUrl100 = "http://is2.mzstatic.com/image/thumb/Music/v4/8e/75/28/8e752885-66d0-737c-11ef-4c706672997e/source/100x100bb.jpg";
    artworkUrl30 = "http://is2.mzstatic.com/image/thumb/Music/v4/8e/75/28/8e752885-66d0-737c-11ef-4c706672997e/source/30x30bb.jpg";
    artworkUrl60 = "http://is2.mzstatic.com/image/thumb/Music/v4/8e/75/28/8e752885-66d0-737c-11ef-4c706672997e/source/60x60bb.jpg";
    collectionCensoredName = Rumours;
    collectionExplicitness = notExplicit;
    collectionId = 594061854;
    collectionName = Rumours;
    collectionPrice = "10.99";
    collectionViewUrl = "https://itunes.apple.com/us/album/the-chain/id594061854?i=594061861&uo=4";
    country = USA;
    currency = USD;
    discCount = 1;
    discNumber = 1;
    isStreamable = 0;
    kind = song;
    previewUrl = "https://audio-ssl.itunes.apple.com/apple-assets-us-std-000001/Music/v4/04/1d/85/041d85eb-f1fe-2d47-1ec7-2540582cece7/mzaf_3322367551095292692.plus.aac.p.m4a?accessKey=1516884136_9174591730773045036_io%2Bc9w6hmWHjPZOpZEgG1nZm9Hm%2FInFnTM%2FT3k8%2BoQZZW2ymomMWeZ8jGkN4TfX85U5U4WRYpxPN8e2svlMmBLE8boGG4aya9izAo%2FIvIMOZ4qt6XPuQQc5JstA%2FmihUGdKsa1Nbov9joyxnTnm7UlpKY2ZsqomfNv4SsJGfDG3cCgxtBoAOKR7Pj42lDYQN1jnRVqusi4Cpf9fHOXb5uA%3D%3D";
    primaryGenreName = Rock;
    releaseDate = "1977-02-04T08:00:00Z";
    trackCensoredName = "The Chain";
    trackCount = 11;
    trackExplicitness = notExplicit;
    trackId = 594061861;
    trackName = "The Chain";
    trackNumber = 7;
    trackPrice = "1.29";
    trackTimeMillis = 270213;
    trackViewUrl = "https://itunes.apple.com/us/album/the-chain/id594061854?i=594061861&uo=4";
    wrapperType = track;
}

If I do a type of check, I get NSDictionary:

print(type(of: dictThisSong))

__NSDictionaryI
__NSDictionaryI
__NSDictionaryI
__NSDictionaryI
__NSDictionaryI
__NSDictionaryI
__NSDictionaryI...

But if I try to print dictThisSong["artistName"] I get a Type "Any" has no subscript members error.

So, then I thought maybe I have to cast to NSDictionary, but that throws an error:

Cannot convert value of type Array to NSDictionary, same if I try to cast to Dictionary

So it seems to me the error message is saying I am trying to cast an Array to a Dictionary but the type of print out says I am already working with a Dictionary. Any help would be appreciated.

Full code:

func parseJSONResults(dictJSON:Dictionary<String, Any>) {

        if let dictData = dictJSON["Data"] as? [String:Any],  let arrResults = dictData["results"] as? Array<Any> {
            for dictThisSong in arrResults {
                print(dictThisSong)
            }
        } else {
            print(dictJSON)
        }


    }

Upvotes: 0

Views: 47

Answers (1)

vadian
vadian

Reputation: 285079

You are fighting the strong type system. Help the compiler than the compiler will help you.

[Any] is an array of I-have-no-idea-what-it-is but you do know that's an array of dictionaries, so cast it to [[String:Any]]

   if let dictData = dictJSON["Data"] as? [String:Any],  
      let arrResults = dictData["results"] as? [[String:Any]] { ...

Upvotes: 1

Related Questions