I am having issues traversing a JSON retrieved from the Google Books API.
I am able to traverse and print the "id" from "items" but how do I get further down the json to print the "title" from "volumeInfo"?
Any tips or pointers appreciated.
JSON from Google:
{
"kind": "books#volumes",
"totalItems": 555,
"items": [
{
"kind": "books#volume",
"id": "BZXn-3QtQ_UC",
"etag": "Phnt2wzOFMo",
"selfLink": "https://www.googleapis.com/books/v1/volumes/BZXn-3QtQ_UC",
"volumeInfo": {
"title": "Revisiting Stephen King",
"subtitle": "A Critical Companion",
"authors": [
"Sharon A. Russell"
],
Swift Code
let url = NSURL(string: "https://www.googleapis.com/books/v1/volumes?q=stephen+king")
NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
if error != nil {
print(error)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers)
if json is [String: AnyObject] {
let items = json["items"] as? [[String: AnyObject]]
for item in items! {
let kind = item["id"] as? String
print(kind)
}
}
} catch let jsonError {
print(jsonError)
}
}.resume()
}
volumeInfo is Dictionary so you need to cast it like [String: AnyObject], and then get the title from that volumInfo Dictionary.
for item in items! {
let kind = item["id"] as? String
print(kind)
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
print(volumeInfo["title"])
}
}
Related
I'm trying to deserialize a json object in swift. The JSON looks like this:
let data = """
{
"code": 200,
"message": "OK",
"results": [
{ "id": 111, "name": "Tony"},
{ "id": 112, "name": "Bill"},
{ "id": 112, "name": "John"}
]
}
""".data(using: .utf8)!
I'm using this to deserialize the JSON
var json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
print (json!["code"]!)
print (json!["message"]!)
print (json!["results"]!)
The correct values are printed in each case, but I can not figure out how to iterate across the value returned by
json!["reults"]
The error message is:
Type 'Any' does not conform to protocol 'Sequence'
Added- after first answer
First answer solves this problem. However, I'm following code from Apple Deveoper's site they do this:
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
for case let result in json["results"] {
if let restaurant = Restaurant(json: result) {
restaurants.append(restaurant)
}
}
And the result they pass in is a String, is this just an old example? Can I continue down this path?
You have to downcast the value of results to an array ([]) of dictionaries ({}). Then iterate the array
let results = json!["results"] as! [[String:Any]]
for item in results {
print(item["name"] as! String, item["id"] as! Int)
}
Side note: In Swift 4+ the Codable protocol is the better choice
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] ?? [:]
if let dictJson = json { //If json is not nil
if let arrResults = dictJson["results"] as? Array<Dictionary<String,Any>>{ //If results is not nil
for result in arrResults {
print(result) //Prints result
}
}
}
Try this. It will iterate result.
i want to show my data in tableview, i have a json data and i have watched this tutorial. It's working but my json data doesn't have array key "actor".
this is example's json data.
{
"actors": [
{
"name": "Brad Pitt",
"description": "William Bradley 'Brad' Pitt is an American actor and film producer. He has received a Golden Globe Award, a Screen Actors Guild Award, and three Academy Award nominations in acting categories",
"dob": "December 18, 1963",
"country": "United States",
"height": "1.80 m",
"spouse": "Jennifer Aniston",
"children": "Shiloh Nouvel Jolie-Pitt, Maddox Chivan Jolie-Pitt",
"image": "http://microblogging.wingnity.com/JSONParsingTutorial/brad.jpg"
},
{
"name": "Tom Cruise",
"description": "Tom Cruise, is an American film actor and producer. He has been nominated for three Academy Awards and has won three Golden Globe Awards. He started his career at age 19 in the 1981 film Endless Love.",
"dob": "July 3, 1962",
"country": "United States",
"height": "1.70 m",
"spouse": "Katie Holmes",
"children": "Suri Cruise, Isabella Jane Cruise, Connor Cruise",
"image": "http://microblogging.wingnity.com/JSONParsingTutorial/cruise.jpg"
}
]
}
it's my json data.
[
{
"ID": 1,
"name": "Amy"
{
"ID": 2,
"name": "John"
}
]
and it's my code;
func downloadJsonWithURL() {
let url = NSURL(string: urlString)
URLSession.shared.dataTask(with: (url as? URL)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
print(jsonObj!.value(forKey: "actors"))
if let studentArray = jsonObj!.value(forKey: "actors") as? NSArray {
for student in studentArray{
if let studentDict = student as? NSDictionary {
if let name = studentDict.value(forKey: "ID") {
self.noArray.append(name as! String)
}
if let name = studentDict.value(forKey: "name") {
self.adiArray.append(name as! String)
}
}
}
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}).resume()
}
i have problem here;
enter image description here
and it will be a problem :/
// my json data doesnt have "actors" ?????
print(jsonObj!.value(forKey: "actors"))
if let studentArray = jsonObj!.value(forKey: "actors") as? NSArray {
for student in studentArray{
if let studentDict = student as? NSDictionary {
Your JSON response is of Array type not the Dictionary. In Swift use native Array instead of NSArray. So you need type cast the jsonObject result to [[String:Any]].
if let array = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [[String:Any]] {
//Now loop through the array.
for item in array {
if let id = item["ID"] as? Int {
self.noArray.append("\(id)")
}
if let name = item["name"] as? String {
self.adiArray.append(name)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Note: Instead of using multiple array you need to use single array of custom object or dictionary, So batter if you create one custom class and made array of it or use array of dictionary.
I recoment to use SwiftyJSON: https://github.com/SwiftyJSON/SwiftyJSON. Easy instal with cocoapods: pod 'SwiftyJSON'
import SwiftyJSON
URLSession.shared.dataTask(with: URL(string: "asd")!, completionHandler: {(data, response, error) in
guard error == nil else {
print("there is an error \(error)")
return
}
guard data != nil else {
print("there is no data")
return
}
let json = JSON(data: data)
for actor in json["actors"].array {
self.noArray.append(actor["ID"].int)
self.adiArray.append(actor["name"].string)
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}).resume()
The first json have root element is Dictionary so your code is working for first json format. But the second json that you want to parse having the root elemt is array and you are trying to assign the array into dictionary that's why you are gettin error So just Replace your code with ..
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options:[]) as? NSArray
Change
as! NSDictionary
To
as! [String : Any]
i've fixed problem.. i chanced jsonObj's line and closed actor's line
this;
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSArray {}
and this
if let actorArray = jsonObj!.value(forKey: "actors") as? NSArray {
for student in jsonObj!{
if let studentDict = student as? NSDictionary {
}
}
I apologise if the title is unclear. I am not quite sure how exactly NSDictionary and JSON works.
I am trying to make a simple app using Swift that takes values from a .JSON file, and prints them out to the console. Here is my JSON file:
{
"students": [
{
"name": "Stew Dent",
"age": "10",
"year": 6,
"grades": [
{
"english": "a-plus",
"math": "b-plus"
},
{
"english": "a",
"math": "a-minus"
}
]
},
{
"name": "Mary Brown",
"age": "14",
"year": 10,
"grades": [
{
"english": "a-plus",
"math": "a-plus"
},
{
"english": "a-plus",
"math": "a"
}
]
}
]
}
Currently, I am able to retrieve the values of everything except the values in "grades". Here is my Swift code:
if let path = Bundle.main.path(forResource: "school", ofType: "json")
{
do {
// Retrieve data from JSON file
let jsonData = try NSData(contentsOfFile: path, options: .mappedIfSafe)
// Convert data into NSDictionary
let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
if let students : [NSDictionary] = jsonResult?["students"] as? [NSDictionary]
{
if let grades : [NSDictionary] = students["grades"] as? [NSDictionary]
{
for grade: NSDictionary in grades
{
for (subject, gradevalue) in grade
{
print ("\(subject): \(gradevalue)")
}
}
}
}
} catch
{
}
}
If I am not wrong, the "grades" is a dictionary inside the "students" dictionary. However, it fails to run the above code. On the "if let grades..." line, it gives the error message: "Cannot subscript a value of type '[NSDictionary]' with an index type of 'String'.
So what I am I doing wrong? Is there even any way to retrieve those values? Am I missing something? Any help would be greatly appreciated. Thanks :)
You should use Swift native types Data instead of NSData and Dictionary [String:Any] instead of NSDictionary. You also forgot to iterate through each student. Try like this:
do {
if let dict = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] {
print(dict)
if let students = dict["students"] as? [[String: Any]] {
print(students)
for student in students {
print(student["name"] ?? "")
if let grades = student["grades"] as? [[String: Any]] {
for grade in grades {
for (subject, gradevalue) in grade {
print ("student:",student["name"] ?? "", "subject:", subject, "grade:", gradevalue)
}
}
}
}
}
}
} catch {
print(error)
}
Try this code, this should work looking at what you are trying to do
if let path = Bundle.main.path(forResource: "student", ofType: "json")
{
do {
// Retrieve data from JSON file
let jsonData = try NSData(contentsOfFile: path, options: .mappedIfSafe)
// Convert data into NSDictionary
let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
if let students = jsonResult?["students"] as? [NSDictionary]
{
for student in students
{
for grades in student["grades"] as! [[String:String]]{
for eachGrade in grades{
print("\(eachGrade.key) : \(eachGrade.value)")
}
}
}
}
}
catch
{
}
}
I have a NodeJS API that queries a MongoDB cluster and returns nearby data in the following format. The issue is I can't enumerate the locations with Swift 3 and XCode 8.1.
[
{
"_id": "57b03fa32c6835946afd358c",
"location": {
"coordinates": [
144.2,
-34
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 01",
"url": "http://www.url.com/Resource01.html"
},
{
"_id": "34b03fa32c6835946afd358c",
"location": {
"coordinates": [
154.2,
-35.3
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 02",
"url": "http://www.url.com/Resource02.html"
}
]
This is my Query code.
let json = try! JSONSerialization.jsonObject(with: data)
print(json)
if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let jsonbranch = statusesArray?[0] as? [String: AnyObject],
let therecord = jsonbranch["_id"] as? String {
print ("_id: " + therecord)
}
I tried to use SwiftyJSON but it does not work either?
Solved:
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[0]["name"] as? String {
print ("name: " + name)
}
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[1]["name"] as? String {
print ("name: " + name)
}
i currently trying to decode Json in Xcode, but i not succed to get one of them.
This is what i get :
[
{
"id": "1",
"title": "bmw",
"price": "500.00",
"description": "330",
"addedDate": "2015-05-18 00:00:00",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "32767",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "2",
"subcategory_label": "Motos",
"bdd": {}
}
"pictures":
[
{ "name": "http://cars.axlegeeks.com/sites/default/files/4315/media/images/2014_BMW_Z4_sDrive28i_3790993.jpg"
}
]
}
]
And i want to get the value of "name" for the "Pictures" lines but i have the error "unexpectedly found nil while unwrapping value".
For the others values i proceed this way :
let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as! NSDictionary
//Browse into JSON to get datas
let resp = jsonData["0"] as! NSDictionary
let user_nameR = resp["user_name"] as! String
let user_zipCodeR = resp["user_zipCode"] as! String
let titleR = resp["title"] as! String
let priceR = resp["price"] as! String
let descriptionR = resp["description"] as! String
Thank's for your help !
Pictures is in not in the subdictionary your other values are. This should work, but you should check all values if they are nil before you force cast them.
if let pictureArray = jsonData["pictures"] as? NSArray
{
if let pictureDict = pictureArray.firstObject as? NSDictionary
{
if let pictureName = pictureDict.objectForKey("name") as? String
{
NSLog("Picture name: %#", pictureName)
}
}
}
jsonData contains two sub-dictionaries, one without a key and one with key 'pictures'. Pictures is an array containing one sub-dictionary.