Parsing JSON Data in Swift from Guidebox API - json

I'm trying to parse JSON Data using Swift from Guidebox. An example of the data is like this:
{
"results": [
{
"id": 14673,
"title": "The Golden Girls",
"alternate_titles": [
"Golden Palace"
],
"container_show": 0,
"first_aired": "1985-09-14",
"imdb_id": "tt0088526",
"tvdb": 71292,
"themoviedb": 1678,
"freebase": "\/m\/01fszq",
"wikipedia_id": 217200,
"tvrage": {
"tvrage_id": 5820,
"link": "http:\/\/www.tvrage.com\/shows\/id-5820"
},
"artwork_208x117": "http:\/\/static-api.guidebox.com\/120214\/thumbnails_small\/14673-9570342022-208x117-show-thumbnail.jpg",
"artwork_304x171": "http:\/\/static-api.guidebox.com\/120214\/thumbnails_medium\/14673-3759246217-304x171-show-thumbnail.jpg",
"artwork_448x252": "http:\/\/static-api.guidebox.com\/120214\/thumbnails_large\/14673-2249565586-448x252-show-thumbnail.jpg",
"artwork_608x342": "http:\/\/static-api.guidebox.com\/120214\/thumbnails_xlarge\/14673-6064109057-608x342-show-thumbnail.jpg"
}
],
"total_results": 1,
"development_api_key": "You are currently using a temporary development API key. This API key is for testing only. You have used 57 of 250 available calls. Please see the API docs (http:\/\/api.guidebox.com\/apidocs) for additional information or to generate a production API key."
}
It seems that for my case, the simplest way to use the data would be to convert it to [String: Any], as all I really need is "id", "title", and an artwork value. However, all of the (countless) methods I have used are failing because of the fact that "alternate_titles" gets parsed as an NSArray and it makes everything more difficult.
So far I've tried variations of this method:
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
let datafinal = jsonResult["results"] as! [String: Any]
//Fails around here usually, when the data is converted to [String: Any] or [Any:Any] because of the array.
let title = datafinal["title"]
} catch {
print("JSON Preocessing failed")
}
I've also used the SwiftyJSON library to try to convert the data to more easily readable JSON, but the methods to pull a dictionary from it always fail (I'm guessing due to the structure as well). Anyone have a simple method to get the JSON data from the URL and easily access the values in "results"? Any help is much appreciated!

Try this
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
let datafinal = jsonResult["results"] as! NSArary
let title = datafinal[0].value(forKey: "title")
print("\(title)")
} catch {
print("JSON Preocessing failed")
}

All you need to do is access results as an array, and take the first element of the array, what is a Dictionary.
In the future, here is great tool, using what you can check the structure of your data more conveniently, and it might reveals problem like this faster.
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
guard let results = jsonResult["results"] as? [Any], let resultDictinary = results.first as? [String: Any] else {
fatalError("Data structure invalid")
}
let title = resultDictinary["title"]
} catch {
print("JSON Preocessing failed")
}

Related

fetch json data into swift uitable view

Below is my json file
and the url is http://localhost/country.php
I want this data into uitable view swift
{ name: ["India","USA","China"] }
let url = NSURL(string: "http://localhost/country.php")
let userdata = NSData(contentsOf: url! as URL)
do {
let values = try JSONSerialization.jsonObject(with: userdata as! Data, options: .allowFragments) as! NSDictionary
print(values)
print("Parse success")
} catch let error as NSError
{
print(error)
return
}
this is the code
please help
So. First of all: Your JSON is not a valid JSON and your URL is (of course) not working. My guess is your JSON looks like that:
{
"name": ["India",
"USA",
"China"
]
}
If so you can change your code like that and it is working as expected:
let jsonString = """
{
"name": ["India",
"USA",
"China"
]
}
"""
let userData = jsonString.data(using: .utf8)!
do {
let values = try JSONSerialization.jsonObject(with: userData) as! [String: Any]
print(values)
print("Parse success")
} catch let error as NSError
{
print(error)
}
Like one comment already mentioned: Try to avoid NStypes in Swift if it is not really needed.
Hope it helps.
And in addition: It is generally a bad practice to load a response from server sync. You should use URLSession and do it async. But this is another thing...
So the full example for your use case would look like this:
let url = URL(string: "http://localhost/country.php")!
let userData = try! Data(contentsOf: url)
do {
let values = try JSONSerialization.jsonObject(with: userData) as! [String: Any]
print(values)
print("Parse success")
} catch let error as NSError
{
print(error)
}
I force unwrap in the example above. I do not recommend that. Savely unwrap your optionals is the better way.

dealing with nested json array swift

I am trying to convert some json data which i receive from a get request into a usable array or something like this
the json data i recieve looks like this
{
"elementlist":{
"Ready Position":{
"Neutral Grip":["1,2,3,4,5"],"
Back Straight (Concave ir Convex?)":["1,2,3,4,5"],"
Body Low & Feet a little more than sholder width apart":["1,2,3,4,5"],"
Weight on Balls of Feet":["1,2,3,4,5"],"
Head Up":["1,2,3,4,5"],"
Sholder Blades Close":["1,2,3,4,5"],"
Eyes Drilled":["1,2,3,4,5"]
},
"Split Step":{"
Ready Position Conforms":["Yes,No"],"
Body Position Low":["1,2,3,4,5"],"
Legs Loaded/Prepared":["1,2,3,4,5"]
}
}
}
this is the swift i am using
let playerAPIurl = "http://linkcoachuat.herokuapp.com/api/v1/session/element?organisation=5&group=green&sport=tennis"
var request = URLRequest(url: URL(string: playerAPIurl)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print("ERROR")
}
else{
do{
print("hello")
let myJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
// Convert myJson into array here
print(myJson)
}
catch
{
}
}}
What i would like to be able to do is get an array of the names of the nested arrays so elementarray = ["Ready Position","Split Step"] and then be able to access the arrays by saying myJson[elementarray[0]] or something similar
im a bit of a swift noob so any help is appreciated please try and explain the answers so they are easily understood
thank you for any help
You can try to downcast that json same way you've already made:
let myJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
//creating the new array of additional elements
let elementArray: [[String: Any]] = []
//making myJson parsing for additional items
if let readyPosition = myJson?["Ready Position"] as? [String: Any] {
elementArray.append(readyPosition)
}
if let splitStep = myJson?["Split Step"] as? [String: Any] {
elementArray.append(splitStep)
}
make print(elementArray) to be sure that all was parsed correctly.
Honestly, I prefer to use objects (custom classes or structs) to store values and have an ability to make related instances or values, but up to you

JSON Serialization not working properly

I've been learning the basics of JSON and I am trying to read data from a JSON file that I have written. The JSON file looks like this:
gradeBoundaries = {
"Subjects": [
{
"Title":"Biology HL",
"Boundaries":
{
1:[0,15],
2:[16,27],
3:[28,39],
4:[40,52],
5:[53,64],
6:[65,77],
7:[78,100]
}
}
]
}
The code that I am using to take the data from this file is as follows:
if let url = Bundle.main.url(forResource: "gradeBoundaries", withExtension: "json") {
do {
let jsonData = try Data(contentsOf: url)
do {
let jsonResult: [([String: String], [String: [Int : [Int]]] )] = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [([String: String], [String: [Int : [Int]]] )] //the entire object
} catch {}
} catch {}
}
When I run the code above, everything works fine until this line:
let jsonResult: [([String: String], [String: [Int : [Int]]] )] = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! [([String: String], [String: [Int : [Int]]] )] //the entire object
As you can see I am trying to cast jsonResult as a fairly complicated data structure. I have tried many others including NSDictionary and Array but none of them seem to make a difference. Since I am so new to JSON I could just be misinterpreting the format of the data, and if anyone could point me in the right direction that would be great.
However, it is indeed nothing to do with the casting, then I am even more lost. This is the way that many SO answers have said to read the data, but it simply does not work for me.
I even tried switching between Data and NSData to no effect. I want to be able to break this data down into smaller pieces, but my program keeps on getting stuck on this line, so I need some help. Thanks!
EDIT
Editing the data type to Any did not allow the line to execute:
let jsonResult: Any = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as! Any
EDIT: 31 Dec 2016
Trying to make it work as below was ineffective:
typealias JSONDictionary = [String: Any]
if let url = Bundle.main.url(forResource: "gradeBoundaries", withExtension: "json") {
do {
let jsonData = try Data(contentsOf: url)
if let jsonResult: JSONDictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? JSONDictionary {
print("success!")
}
} catch {}
}
However, it seems like a really good idea, so I think there must be something seriously wrong about my JSON or I'm doing something really stupid in my code.
EDIT
The JSON that I have been using is apparently invalid. I modified it now to be this:
{
"Subjects": [
{
"Title":"Biology HL",
"Boundaries":
{
1:[0,15],
2:[16,27],
3:[28,39],
4:[40,52],
5:[53,64],
6:[65,77],
7:[78,100]
}
}
]
}
First of all a message to all writers of online tutorials:
Please stop suggesting the reading option .mutableContainers in Swift. It's completely meaningless because mutability is provided for free by assigning the object to a variable.
Don't confuse yourself by annotating that weird snake-type.
To understand the structure read the hierarchy. [] is an array, {} a dictionary.
For convenience declare a type alias for a JSON dictionary
typealias JSONDictionary = [String:Any]
Then walk through the JSON (assuming the root object is a dictionary):
do {
if let jsonResult = try JSONSerialization.jsonObject(with:jsonData, options: []) as? JSONDictionary {
if let subjects = jsonResult["Subjects"] as? [JSONDictionary] {
for subject in subjects {
print(subject["Title"] as? String)
if let boundaries = subject["Boundaries"] as? JSONDictionary {
for (key, value) in boundaries {
print(key, value)
}
}
}
}
}
} catch {
print(error)
}
Regarding the JSON the keys in the Boundary dictionary must be strings:
{
"Subjects": [
{
"Title":"Biology HL",
"Boundaries":
{
"1":[0,15],
"2":[16,27],
"3":[28,39],
"4":[40,52],
"5":[53,64],
"6":[65,77],
"7":[78,100]
}
}
]
}
So I figured it out and feel like an idiot. After using Java and Swift for the longest time, I thought I would leave some comments on my JSON.
The JSON I was actually using was this:
{
"Subjects": [//[([String: String], [String: [Int : [Int]]] )]
{
"Title":"Biology HL", //[String: String]
"Boundaries": //[String: [Int: [Int]]]
{
"1":[0,15], //[Int: [Int]]
"2":[16,27],
"3":[28,39],
"4":[40,52],
"5":[53,64],
"6":[65,77],
"7":[78,100]
}
}
]
}
However, I thought that I would leave the comments out of the SO question because they weren't necessary.
After copying #vadian's suggested JSON my code worked. I then came up with this hypothesis and tried adding a comment to his JSON, and needless to say it didn't work.
So I guess the moral of this story is read up about commenting on code before you actually do it.

"Expression Implicity Coerced from 'String?' to Any" JSON Swift 3

Hi I have the below JSON code I would like to parse
"data":{
"date":"November 30th, 2016",
"personality":"Larry",
"comment":"Saw the homie today"
},
I'm doing this in my viewDidLoad
let url=URL(string:"http://IP-ADDRESS/info.php")
do {
let allNotificationsData = try Data(contentsOf: url!)
let allNotication = try JSONSerialization.jsonObject(with: allNotificationsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allNotication["notifications"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as? [String: AnyObject]
//let name = aObject?["data"]!
if let jsonResponse = aObject,
let info = jsonResponse["data"] {
// Makes sense to check if count > 0 if you're not sure, but...
let transaction_id: String? = info["personality"] as? String
print(transaction_id)
// Do whatever else you need here
}
Which seems to be fine but console returns below. Not sure while "nil" but I just want it show me "date" in the JSON file itself only in the console. Eventually I'll need it to catch an array of dates, not sure how I'll do that but I'm working on it. Let me know if you know what I'm doing wrong. It has to be something with optional.
Assuming the parent object of data is an array (your code suggests that) you can get all data objects in an array with:
do {
let allNotificationsData = try Data(contentsOf: url!)
let allNotification = try JSONSerialization.jsonObject(with: allNotificationsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String:Any]
if let arrJSON = allNotification["notifications"] as? [[String:Any]] {
let infoArray = arrJSON.flatMap { $0["data"] }
}
...
}
The benefit of flatMap is it ignores nil values.
If you want to access the comment value of the first item in the array write
let comment = (infoArray[0] as! [String:Any])["comment"] as! String

Parsing JSON using Swift 3

I have this json data that I want to consume in Swift 3. I'm learning Swift and building a very basic app that displays the list of items in tableUIView from JSON.
{
"expertPainPanels" : [
{
"name": "User A",
"organization": "Company A"
},
{
"name": "User B",
"organization": "Company B"
}
]
}
I'm trying to get this data using Swift 3.
if (statusCode == 200) {
do{
let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments) // [[String:AnyObject]]
/*
If I do this:
let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String:Any]
if let experts = json?["expertPainPanels"] as! [String: Any] {
I get "Initializer for conditional binding must have Optional type, not '[String: Any]'"
*/
// Type 'Any' has no subscript members.
if let experts = json["expertPainPanels"] as? [String: AnyObject] {
for expert in experts {
let name = expert["name"] as? String
let organization = expert["organization"] as? String
let expertPainPanel = ExpertPainPanel(name: name, organization: organization)!
self.expertPainPanels += [expertPainPanel]
self.tableView.reloadData()
self.removeLoadingScreen()
}
}
}catch {
print("Error with Json: \(error)")
}
}
It was working fine in Swift 2. I updated to Swift 3 which broke the code. I read several SO, but I still have hard time understanding it. I applied some suggestions including JSON Parsing in Swift 3, but I'm still unable to fix the error I'm getting.
As of Swift 3, you need to do a cast early on.
This line:
let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments)
Should become this:
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as? [String : AnyObject]
This is because JSONSerialization now returns Any, which does not implement a variation for the [] operator. Make sure you safely unwrap the cast and take the common measures to ensure you don't crash your program.
Edit: Your code should more or less look like this.
let data = Data()
let json = try JSONSerialization.jsonObject(with: data, options:.allowFragments) as! [String : AnyObject]
if let experts = json["expertPainPanels"] as? [String: AnyObject] {