Swift :: Traverse a json string - json

Here is a string looks like a json.
let text2 = " [{ \"insertion_date\" :\""+"2015-07-31 11:21:04 +0000"+"\",\"mood\": \""+"Happy"+"\",\"temperature\": \""+"22"+"\"},{ \"insertion_date\" :\""+"2015-07-31 11:21:04 +0000"+"\",\"mood\": \""+"Sad"+"\",\"temperature\": \""+"22"+"\"}]"
I can access the whole string like this.
var data = text2.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
var json3: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)
println(json3)
But now I want to access individual element of this string, like - I want to access the second "mood" key, which has the value "Sad".
How can I access it?

You could use something like this:
var jsonArr: NSArray! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) as! NSArray
for dict in jsonArr {
print(dict.objectForKey("mood"))
}
Which will print each of the moods.

Swift's native JSON parsing is a pain due to all the optional unwrapping:
if let days = json3 as? NSArray {
if let secondDay = days[1] as? NSDictionary {
let mood = secondDay["mood"] as! String
print(mood)
}
}
You can use other framework like SwiftyJson for an easier time.

You can also use Swift's native types instead of NSArray and NSDictionary, and cast the result of NSJSONSerialization as an array of dictionaries ([[String:AnyObject]]):
if let json3 = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: &localError) as? [[String:AnyObject]] {
for dict in json3 {
if let mood = dict["mood"] as? String {
println(mood)
}
}
}
Note also that you don't need to give specific options to NSJSONSerialization, you can pass nil in this case.
If you're absolutely certain that your values will always be of type String, you can also cast the result directly (and avoid later casts when accessing values):
if let json3 = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: &localError) as? [[String:String]] {
for dict in json3 {
if let mood = dict["mood"] {
println(mood)
}
}
}

Related

Can not parse nested dictionary

I want to parse this JSON data, but I can't make it.
JSON data is like
My code is:
session.dataTask(with: request, completionHandler:{( data , response , error) -> Void in
if let data = data {
if let jsonObj = try? JSONSerialization.jsonObject(with: data , options: .allowFragments) as! Any {
print(jsonObj)
if let postdata = (jsonObj as AnyObject).value(forKey: "postdata") {
print(postdata)
//if let something = postdata["best_before"] as? NSDictionary{
// print(something)
The root object is clearly a dictionary ([String:Any]) not just something (Any) and use proper error handling and optional bindings to unwrap the optionals safely.
The value for key postdata is an array of dictionaries ([[String:Any]]). And don't use valueForKey – and by the way those silly bridge casts to AnyObject – unless you can explain why you explicitly need KVC.
.allowFragments is not needed because the root object is a collection type.
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data) as? [String:Any],
let postdata = jsonObj["postdata"] as? [[String:Any]] {
for data in postdata {
for (key, value) in data {
print(key, value)
}
}
}
} catch {
print(error)
}

Parsing string json in swift 3

I have a json saved in String format and I´m trying to use:
let json = "{'result':[{'name':'Bob','age':'27'}]}";
Using JSONSerialization comes error about Cannot invoke jsonOject with an argument...
if let json = try JSONSerialization.jsonObject(with: json) as? [String: Any],
let array = json["result"] as? [[String: Any]] {
for item in array {
if let name = item["name"] as? String {
if name == "Bob" {
self.age = Int((item["age"] as? String)!)!
}
}
}
}
I tryed to use this solution but with no success.
Please look at the declaration of jsonObject(with) by ⌥-click on the symbol.
The first parameter is of type Data so you have to convert String to Data.
A major issue is that the JSON is not formatted correctly. The string indicators must be double quotes.
let json = "{\"result\":[{\"name\":\"Bob\",\"age\":27}]}"
let jsonData = json.data(using: .utf8)
do {
if let result = try JSONSerialization.jsonObject(with: jsonData!) as? [String: Any],
...
self.age = item["age"] as! Int

"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

Strange behaviour of optionals in Swift 3

I have experienced a strange behaviour when parsing JSON data using Swift 3.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary
let items:[AnyObject] = (json["items"] as? [AnyObject])!
for item in items {
let id:String = item["id"] as! String
print("ID: \(id)")
let info = item["volumeInfo"] as AnyObject
print(info)
let title = info["title"]
print(title)
}
} catch {
print("error thrown")
}
This produces the following output. Notice that info is an optional but if I try to unwrap it it states it is not an optional! The script crashes on let title = info["title"] As a result I can't access the title key. This behaviour has changed since Swift 2.
ID: lbvUD6LUyV8C
Optional({
publishedDate = 2002;
publisher = "Sams Publishing";
title = "Java Deployment with JNLP and WebStart";
})
You can do something like:
do {
let json = try JSONSerialization.jsonObject(with: data!) as! [String: Any]
let items = json["items"] as! [[String: Any]]
for item in items {
let id = item["id"] as! String
let info = item["volumeInfo"] as! [String: Any]
let title = info["title"] as! String
print(id)
print(info)
print(title)
}
} catch {
print("error thrown: \(error)")
}
I might suggest excising the code of the ! forced unwrapping (if the JSON was not in the form you expected, do you really want this to crash?), but hopefully this illustrates the basic idea.
The runtime type of info is Optional<Something>, but the compile time type (as you explicitly cast it) is AnyObject. How is the compiler supposed to know that the AnyObject will happen to be an Optional<Something> unless you tell it (in the form of a cast)?
Try:
let info = item["volumeInfo"] as AnyObject?
Now the compiler knows it's an Optional<AnyObject>, so you can unwrap it.
In Swift 3 the compiler must know the types of all subscripted objects if it's an array or dictionary. AnyObject – which has been changed to Any in Swift 3 – is not sufficient.
Since you know that the value for key volumeInfo is a dictionary cast it accordingly preferably using optional bindings
let info = item["volumeInfo"] as? [String:Any] {
print(info)
let title = info["title"] as! String
print(title)
}
This should do:
guard let json = try? JSONSerialization.jsonObject(with: data!, options: []) as! [String: AnyObject],
let items = json["items"] as! Array<AnyObject>? else {
return
}
for item in items {
let id = item["id"] as! String
if let info = item["volumeInfo"] as? [String: AnyObject] {
let title = info["title"] as! String
} else {
// do something
}
}

How to parse this specific JSON data in Swift 2.0

I'm trying to parse Json Data from an API :
{
"title": "Mr. Robot",
"first_aired": "2015-06-24",
"network": "USA Network",
"channels": [
{
"id": 12,
"name": "USA",
"short_name": "usa",
"channel_type": "television"
}
],
The Code I'm use is:
var TVArray : [TVInfo] = []
var task : NSURLSessionTask?
func getJSON (urlString: String) {
let url = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
task = session.dataTaskWithURL(url) {(data, response, error) in
dispatch_async(dispatch_get_main_queue()) {
if (error == nil) {
self.updateJSON(data)
}
else {
}
}
}
task!.resume()
}
func updateJSON (data: NSData!) {
let JSONData = (try! NSJSONSerialization.JSONObjectWithData(data, options: []))
TVArray.removeAll(keepCapacity: true)
if let jsonArray = JSONData {
for j in jsonArray {
let title = jsonResult["title"] as! String
let firstAired = jsonResult["first_aired"] as! String
let network = jsonResult["network"] as! String
let channelName = JsonResult["channels"][0]["name"] as! String
let TV = TVInfo(title: title, firstAired: firstAired, network: network, channelName: channelName)
TVArray.append(TV)
}
}
collectionview.reloadData()
}
}
When I use the above code I get an error 'Initializer for conditional binding must have Optional type, not 'AnyObject'' in front of the line 'if let jsonArray = JsonData'. I've tried some methods I've seen on StackOverflow like the method in the link :
[Parsing JSON in swift 2.0
but it didn't work for me. I'm still a bit new to Swift, I really don't want to use SwiftyJSON. Is this the best way to parse this JSON data or is there a better way of doing it?
Since you've used NSJSONSerialization with try! (note the !, meaning it was forced) the value of JSONData is not an optional: you don't have to unwrap it with if let jsonArray = JSONData.
If you still want an optional value, use try? instead.
Otherwise you could also use try inside a do catch block to handle possible errors.
The type of JSONData is unknown, it needs to be known to be an Array for the following for loop.
use:
let JSONData = try! NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! NSArray
You do not need:
if let jsonArray = JSONData {
because you have already crashed if JSONData is nil from the preceding try!
You are better with:
do {
let jsonArray = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! NSArray
for j in jsonArray {
// ...
}
} catch {
// handle error
}
Because you have no control over the JSON you receive and crashing because of a server change is not a good idea.
Also really put some time into naming variables, JSONData is not data, it is an array obtained by parsing a JSON string.