Issue
I’m trying to access indices of an NSDictionary, and convert that key’s value to an Int using Swift.
I’m also using an API to fetch data. The API response is what I’m using to create an initial dictionary out of, then I create a dictionary out of the “hours” part of the API response. The API call part of my code is working, so I’ve only included code related to accessing the hoursDictionary.
I’ve tried using [[[String: Any]]] instead of [NSDictionary] for hoursDictionary after looking up this problem online, but this did not work for me.
The error I keep getting is at the if statement line: if Int(hoursDictionary[0][5][2]) > Integer for a certain time { , and the error text is: “Value of type ‘Any?’ has no subscripts”. I know this is because the NSDictionary’s key’s value that I’m trying to access has a value of type Any.
I think the error is somewhere in this if statement, and is related to changing the data type of that part in the dictionary that I’m trying to access to an Int.
The API that I’m using is the Yelp Fusion API, and the API search that I’m using is “Business Details”. Here’s a link to this documentation: https://www.yelp.com/developers/documentation/v3/business .
An example of the API response body that is being returned and what I’m accessing is the following:
{
"id": "WavvLdfdP6g8aZTtbBQHTw",
"alias": "gary-danko-san-francisco",
"name": "Gary Danko",
"image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/CPc91bGzKBe95aM5edjhhQ/o.jpg",
"is_claimed": true,
"is_closed": false,
"url": "https://www.yelp.com/biz/gary-danko-san-francisco?adjust_creative=wpr6gw4FnptTrk1CeT8POg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_lookup&utm_source=wpr6gw4FnptTrk1CeT8POg",
"phone": "+14157492060",
"display_phone": "(415) 749-2060",
"review_count": 5296,
"categories": [
{
"alias": "newamerican",
"title": "American (New)"
},
{
"alias": "french",
"title": "French"
},
{
"alias": "wine_bars",
"title": "Wine Bars"
}
],
"rating": 4.5,
"location": {
"address1": "800 N Point St",
"address2": "",
"address3": "",
"city": "San Francisco",
"zip_code": "94109",
"country": "US",
"state": "CA",
"display_address": [
"800 N Point St",
"San Francisco, CA 94109"
],
"cross_streets": ""
},
"coordinates": {
"latitude": 37.80587,
"longitude": -122.42058
},
"photos": [
"https://s3-media2.fl.yelpcdn.com/bphoto/CPc91bGzKBe95aM5edjhhQ/o.jpg",
"https://s3-media4.fl.yelpcdn.com/bphoto/FmXn6cYO1Mm03UNO5cbOqw/o.jpg",
"https://s3-media4.fl.yelpcdn.com/bphoto/HZVDyYaghwPl2kVbvHuHjA/o.jpg"
],
"price": "$$$$",
"hours": [
{
"open": [
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 0
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 1
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 2
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 3
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 4
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 5
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 6
}
],
"hours_type": "REGULAR",
"is_open_now": false
}
],
"transactions": [],
"special_hours": [
{
"date": "2019-02-07",
"is_closed": null,
"start": "1600",
"end": "2000",
"is_overnight": false
}
]
}
Snippet of my code:
FetchData.swift
/// Read data as JSON
let json = try JSONSerialization.jsonObject(with: data!, options: [])
/// Main dictionary
guard let responseDictionary = json as? NSDictionary else {return}
/// Creating hours dictionary,
guard let hoursDictionary = responseDictionary.value(forKey: "hours") as? [NSDictionary] else {return}
if let endTimeAsString = hoursDictionary["open"][5]["end"] as? String,
let endTimeAsInt = Int(endTimeAsString),
endTimeAsInt > An integer representing a certain time {
// Do something
}
Solution
You can’t access a dictionary’s [nth] index like you would an array because a dictionary is an unordered collection. Instead you would have to do something like this [CORRECTED] hoursDictionary[0]["open"][5]["end"]
, or whatever sequence to get the value you need.
Or, I tend to split this up so I can ensure I am processing each step correctly like so:
guard let hoursDictionaries = responseDictionary.value(forKey: "hours") as? [NSDictionary] else {return}
if let firstHoursDictionary = hoursDictionaries[0] as? NSDictionary,
let openDictionarys = firstHoursDictionary["open"] as? [NSDictionary],
let firstOpenDictionary = openDictionarys[5] as? NSDictionary,
let endTimeAsString = firstOpenDictionary["end"] as? String,
let endTimeAsInt = Int(endTimeAsString),
endTimeAsInt > someInt {
// Do something
}
// Remember, you can always check what type the compiler is inferring something
// to be by right-clicking on the variable name and clicking `Show Quick Help`.
Answered By – Eric33187
Answer Checked By – Cary Denson (BugsFixing Admin)