Reputation: 67
I have a JSON object that looks like this:
{
geometry = {
location = {
lat = "51.5194133";
lng = "-0.1269566";
};
};
id = ad6aaec7b7b0fa2c97a127c24845d76135e760ae;
"place_id" = ChIJB9OTMDIbdkgRp0JWbQGZsS8;
reference = "CmRRAAAAiC-ErdlAvz74Drejj2mAAh6Plr46e889a3Uv6CrRXFqNtVatoFsOTarDH0KU8KCkWoN--QGv01RSjLBZblbrAHNPGDVdiXikedid0vKMVM_LQtXstrSQFt4s-Z-Wi-1AEhDJRWc9bdWpKHPPOrt7QGTqGhSJgMPENn_wSGbprGYLv52csv5BtQ";
}
I was wondering how you can extract the information at different levels. For example, the location object is an object within the geometry object and I want to extract lat from there how can I do this?
I can print out the location object like:
let setOne = jsonResult["results"]! as! NSArray
let y = setOne[0] as? [String: AnyObject]
print(y!)
print((y!["geometry"]!["location"]!)!["lat"])
but when I try to do:
print((y!["geometry"]!["location"]!)!["lat"])
it gives me the error:
Type 'Any' has no subscript members
Upvotes: 0
Views: 341
Reputation: 611
Considering you have an array of data as results (jsonResult), start accessing your array and identify the type of each parameter.
if let resultArray = jsonResult["results"] as? NSArray {
for aResult in resultArray {
//using "if let" simply means, in this case, if "geometry" is indeed a dictionary it will execute the statement/s inside this "if" block.
if let geometry = aResult["geometry"] as? NSDictionary {
if let location = geometry["location"] as? NSDictionary {
if let latValue = location["lat"] as? String {
//This will only be executed if the value is String
print(latValue)
}
if let lngValue = location["lng"] as? String {
print(lngValue)
}
}
}
}
}
Upvotes: 0
Reputation: 9352
Perhaps the easiest way to do this is to use JSONDecoder
to decode your JSON directly into structs.
You first need to define structs that match your JSON structure, like so:
struct Place: Codable {
let geometry: Geometry
let id: String
let place_id: String
let reference: String
}
struct Geometry: Codable {
let location: Location
}
struct Location: Codable {
let lat: String
let lng: String
}
Now, assuming that jsonResult["results"]
is in fact an NSArray
, you first need to convert it to Data
and then use the JSONDecoder
to decode the JSON into the structs:
if let data = try? JSONSerialization.data(withJSONObject: jsonResult["results"], options: []) {
if let places = try? JSONDecoder().decode(Array<Place>.self, from: data) {
print(places[0].geometry.location.lat) //prints "51.5194133"
}
}
The advantage of this approach is that you write much less code to do the actual decoding.
Note that if any of the JSON elements might be missing, you should declare the corresponding struct let
property as an optional. For example, if reference
might not always be present, you would code it as:
let reference: String?
Anything that is not optional must be present in the JSON, or the decode will fail. This is why you want to use try?
when decoding, so that your app does not crash.
Upvotes: 2
Reputation: 8396
Lets say you have an array of results data, you don't need to use NSArray since you are using Swift so here you can start.
In Swift you need to specify the type, And also try not to use AnyObject unless you really need it, Always provide the type and thats what the error is saying:
// make sure that results exist
if let resultArray = jsonResult["results"] as? [Dictionary<String,Any>] {
// loop through the result array
for object in resultArray {
// get geometry from the object in the array
if let geometry = object["geometry"] as? Dictionary<String,Any>{
// make sure it has location
if let location = geometry["location"] as? Dictionary<String,Any>{
// now get the lat or lng safely.
let lat = location["lat"] as? String ?? "0.0"
let lng = location["lng"] as? String ?? "0.0"
}
}
}
}
Note: Never use force-unwrap ! because your app will crash if something went wrong or that specific object is not found, make sure to use guard let
or if let
at least, although this is manual parsing you can look into Swift 4 new Encoding, Decoding and Serialization in Swift 4.
Upvotes: 0