Thanks. Generally, when you cannot get some item which surely exists in a JSON response, checking the whole response might be needed. Better remember the debugging code print(String(data: data, encoding: .utf8) ?? "?").this is the first part of the output leading up to "results":
To summarize, the response outlined looks like this:
Code Block { "html_attributions" : [], "next_page_token" : "...", "results" : [...], "status" : "OK" }
It is a JSON object containing 4 entries, "html_attributions", "next_page_token", "results" and "status".
JSON object is represented as [String: Any] in Swift, or as NSDictionary in Objective-C.
So, your original code as? NSDictionary or my previous code as? [String: Any] does work.
And the value for "results" is a JSON array, which contains JSON objects.
Each element looks like this:
Code Block { "business_status" : "OPERATIONAL", "geometry" : { "location" : { "lat" : 37.3514093, "lng" : -122.0017734 }, "viewport" : { "northeast" : { "lat" : 37.35274472989272, "lng" : -122.0004817701073 }, "southwest" : { "lat" : 37.35004507010728, "lng" : -122.0031814298927 } } }, "icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/restaurant-71.png", "name" : "Roll N Noodle Food Court", "opening_hours" : { "open_now" : false }, "photos" : [ { "height" : 3024, "html_attributions" : [ "\u003ca href=\"https://maps.google.com/maps/contrib/100046552616844334295\"\u003eA Google User\u003c/a\u003e" ], "photo_reference" : "ATtYBwINYsbf5B1ox6_R1Du0EXIS3FxUl5Pg5W-ligjn41HHs14trlNGNpFey4vCGOmI_VWS1qT9F0Z3VjdXxvy3r8QYt42GtEBaAcoij9aRTzS6z0jnUkcuGrzi_AGixmDj_iiB-g3eYSZBCmbzDx1xJ3nmotgEW1INqY_Ddgi4PC4U78Ke", "width" : 4032 } ], "place_id" : "ChIJYya4KWe1j4ARw8nBr2iSdSI", "plus_code" : { "compound_code" : "9X2X+H7 Sunnyvale, California", "global_code" : "849V9X2X+H7" }, "rating" : 4.9, "reference" : "ChIJYya4KWe1j4ARw8nBr2iSdSI", "scope" : "GOOGLE", "types" : [ "restaurant", "food", "point_of_interest", "establishment" ], "user_ratings_total" : 13, "vicinity" : "1092 E El Camino Real, Sunnyvale" },
It can be outlines as follows:
Code Block { "business_status" : "OPERATIONAL", "geometry" : {...}, "icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/restaurant-71.png", "name" : "Roll N Noodle Food Court", "opening_hours" : {...}, "photos" : [...], "place_id" : "ChIJYya4KWe1j4ARw8nBr2iSdSI", "plus_code" : {...}, "rating" : 4.9, "reference" : "ChIJYya4KWe1j4ARw8nBr2iSdSI", "scope" : "GOOGLE", "types" : [ "restaurant", "food", "point_of_interest", "establishment" ], "user_ratings_total" : 13, "vicinity" : "1092 E El Camino Real, Sunnyvale" },
There are several entries, but no entries for "location".
There is an entry for "name" and its value is a JSON string, so your result["name"] as? String does work.
But there aren't any entries for "location", result["location"] fails before evaluating as? String.
Assume you want to get the following info which is embedded in the value for "geometry":
Code Block "location" : { "lat" : 37.3514093, "lng" : -122.0017734 },
You may need to dig into "geometry".
The value for "geometry" is a JSON object, so you need to write something like this:
Code Block guard let geometry = result["geometry"] as? [String: Any] else { print("value for `geometry` not found or not object") return // or throw some error or ignore and continue }
And then, the value for "location" is a JSON object:
Code Block guard let location = geometry["location"] as? [String: Double] else { print("value for `location` not found or not object") return // or throw some error or ignore and continue }
In "location", the values are all numbers, so [String: Double] is used instead of [String: Any].
Code Block guard let lat = location["lat"], let lng = location["lng"] else { print("value for `lat` or `lng` not found or not number") return // or throw some error or ignore and continue }
With all these guard-lets, you can use lat and lng as Swift Double.
You may need to update your locationArray like this:
Code Block var locationArray: [CLLocationCoordinate2D] = []
And use it as:
Code Block let coord = CLLocationCoordinate2D(latitude: lat, longitude: lng) self.locationArray.append(coord)
The do-catch part would look like this with all above things included:
Generally, keeping two (or more) Arrays consistent would be difficult. So, having two Arrays separately like nameArray and locationArray is not considered to be a good practice. It may be too much to include into this thread.
Please try the new code above.
If you feel many guard-lets sort of annoying, you should better learn and try Swift Codable.
With more simple APIs...