Swift - Forming an array from a JSON Response - ios

I am new to the world of JSON. I just got started with JSON in Swift.
Right now, I have the following function:
func forShow() {
// Using ACORN API to fetch the course codes
guard let url[enter image description here][1]Online = URL(string: "https://timetable.iit.artsci.utoronto.ca/api/20179/courses?code=CSC") else { return }
let session = URLSession.shared
session.dataTask(with: urlOnline) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
} catch {
print(error)
}
}
}.resume()
}
I get a response with all courses having 'CSC' in their code String. I want to form an array with all complete course codes based on the response. I will paste response for one course here:
So, I want to access all the course codes seen in the image. It's "CSC104H1-F-20179" I want to to be able to access.

Treat your JSON like a dictionary. You have all the course names at the top level, so fortunately you don't have to dig deep in the hierarchy.
So, where you have:
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
Change to:
if let arrayOfCourses = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] {
for (course, _) in arrayOfCourses {
print(course)
}
}

Related

jsonObject(with: data) succesfully reading valid json, but not returning valid json

I am dealing with some issues with the following code:
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
if let data = data {
let string1 = String(data: data, encoding: String.Encoding.utf8) ?? "Data could not be printed"
print(string1)
do {
if let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
print("success")
print(jsonData as AnyObject)
}
} catch {
print(error.localizedDescription)
}
}
}.resume()
When I print out string1 it is valid json and the line print("success") gets executed. However, when it reaches print(jsonData as AnyObject) the output is similar to json, but there are = in place of : and () in place of []. In addition to this, some of the keys aren't even strings. It looks as follows:
(
{ "build_path" = "<null>";
city = "<null>";
cm = "<null>";
country = "<null>";
}, {
//similar to above
}
)
(the values are actually currently null)
I'm not really sure why this is happening so any help is appreciated. Thanks.
Remove as AnyObject in print(jsonData as AnyObject). It will print in the format you are expecting.
I looked through some old code, so try with the following line for the JSONSerialization part:
if let jsonData = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:Any]
I got the correct result when just:
print(jsonData)
Hope this helps.

Multidimensional array/dictionary loop in Swift

I'm trying to loop through a multidimensional array/dictionary in Swift which I got from a JSON string. Originally I come from PHP so I'm probably a bit off with my approach.
My issue is that I can't seem to get into a sub-array/dict.
My code so far:
func getJSON(){
let url = NSURL(string: url)
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!)
let array = jsonObj!.allKeys
for keys in array {
print(keys)
}
OperationQueue.main.addOperation({
//Nothing to do right now
})
}
}).resume()
}
My JSON:
{
"ArrayName1": {
"info": "This is my first array!",
"more": "Even more info!"
},
"ArrayName2": {
"info": "This is my second array!",
"more": "Even more info about the second array!"
}
}
The function prints the key (e.g. ArrayName1) which is good, but how do I get deeper into the array? To print the "info"?
If you are sure it's dictionary in this form [String: [String: Any]], you may want to try this.
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: [String: Any]] {
let array = jsonObj!.allKeys
for key in array {
print(key)
let info = jsonObj[key]["info"] as! String
}
}
First of all don't use NSURL in Swift 3. There is a native struct URL.
Second of all .allowFragments is useless as the JSON is clearly a collection type.
Third of all don't use NSDictionary in Swift, use native type Dictionary.
Fourth of all do the error handling at least the possible error passed by the data task.
All collection types are dictionaries. Use Fast Enumeration to parse keys and values. All keys and values are strings.
func getJSON(){
let url = URL(string: url)!
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) -> Void in
if error != nil {
print(error!)
return
}
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data!) as? [String:[String:String]] {
for (key, innerDictionary) in jsonObj {
print(key)
if let info = innerDictionary["info"] {
print("info", info)
}
}
DispatchQueue.main.async {
//Nothing to do right now
}
} else { print("The JSON object is not [String:[String:String]]") }
} catch {
print(error)
}
}).resume()
}

iOS Swift Casting JSON response with strange format to dictionary

I'm attempting to cast a JSON response in swift to a useable dictionary. This seemed like a simple task, however the JSON response I am getting is formatted strangely, and no matter what I try, I am unable to cast it to a dictionary. All of the google examples I've been able to find assume that the format of the JSON response will be as follows:
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
},
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
}
However, the print response in swift I'm receiving using the code below is formatted as follows:
{assets = (
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
},
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
}
);
}
Here is as far as I was able to get in attempting to cast this data to a dictionary in swift. It adds "assets" as the single key in the dictionary, with the value of that key being the entire rest of the response.
let url = URL(string: "https://\(apiKey):\(password)#\(yourStore).myshopify.com/admin/themes/\(currentThemeID)/assets.json")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: [.allowFragments, JSONSerialization.ReadingOptions.mutableContainers])
print(jsonResult)
if let dictionary = jsonResult as? [String: [String]] {
print(dictionary)
}
} catch {
print("json processing failed")
}
}
}
}
task.resume()
I'm pretty sure the hang up resides around the presence of the two "parenthesis" and "semi-colon" in the JSON response. I'm unable to find any documentation on how those characters effect the response, or on how to handle them when attempting to down-cast in swift.
Any help would be appreciated!
EDIT:
I've pulled up the JSON response in my browser, and here is the formatting:
{"assets":[{"key":"assets\/1-1.png","public_url":"https:\/\/cdn.shopify.com\/s\/files\/1\/0810\/2125\/t\/22\/assets\/1-1.png?5272098227851596200","created_at":"2016-05-16T16:58:27-05:00","updated_at":"2016-05-16T16:58:27-05:00","content_type":"image\/png","size":9127,"theme_id":124078279}{"key":"templates\/search.liquid","public_url":null,"created_at":"2016-05-16T16:59:04-05:00","updated_at":"2016-05-16T16:59:04-05:00","content_type":"text\/x-liquid","size":2931,"theme_id":124078279}]}
This JSON response does not have the assets = (); portion in it, and is formatted correctly. Somehow my swift code is improperly parsing the data?
Repeatedly cast as [String: Any] to get down to the part of the JSON response you want.
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: [.allowFragments, JSONSerialization.ReadingOptions.mutableContainers])
print(jsonResult)
guard
let dictionary = jsonResult as? [String: Any],
let assetData = dictionary["assets"] as? [String: Any] else {
print("The JSON structure doesn't meet our expectations \(urlContent)")
return
}
print(assetData)
} catch {
print("json processing failed")
}

NSJSONSerialization Error : Why am I not able to catch the error in try catch block? swift 3.0

I am calling REST API to get a response from the server and also testing for bad data type to caught in try catch block nut app still crashes with below error:
Could not cast value of type '__NSArrayM' (0x10575ee00) to 'NSDictionary' (0x10575f2d8).
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error!)
return
}
do {
let responseObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,String>
print(responseObject)
} catch let jsonError {
print(jsonError)
}
}
dataTask.resume()
For this, I also found the solution that I should check data with JSON format first then use JSONSerialization.
if JSONSerialization.isValidJSONObject(data){
responseObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,String>
}
else {
print("Error")
}
I want to know that if type cast value error not caught by the try-catch block then what is a use of try-catch block in network call. I can simply check for the JSON format and the pass the response object.
What is a good programming practice?
NOTE : Error is not an issue I just don't want my should crash an app when data type changes form dictionary to array or other than specified type.
This is not about valid JSON, you are getting this crash because your JSON at root is Array not Dictionary and you are trying to cast the result of jsonObject(with:) to Dictionary that is the reason you are getting this crash also there is no need to specify mutableContainers with Swift.
do {
let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as! [[String:Any]]
print(responseObject)
} catch let jsonError {
print(jsonError)
}
Edit: If you don't know your JSON time then you can use if let like this way.
do {
let responseObject = try JSONSerialization.jsonObject(with: data, options: [])
if let responseArray = responseObject as? [[String:Any]] {
//Access array
}
else if let responseDictionary = responseObject as? [String:Any] {
//Access dictionary
}
print(responseObject)
} catch let jsonError {
print(jsonError)
}

Reading Data in API response | iOS

I'm trying to integrate a login API in my iOS project. When i hit that API in browser it gives me correct JSON response. Whereas, when i call it in my app, i'm unable to read JSON. Code is as:
let url = NSURL(string: "myURL")
let request = NSURLRequest(URL: url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
print (error)
}
do {
//jsonDict is always nil
if let jsonDict = try self.jsonFromData(data!) {
print (jsonDict)
}
}
catch {
print ("hi")
}
}
jsonFromData is as:
private func jsonFromData(jsonData: NSData) throws -> [NSDictionary]?
{
var jsonDict: [NSDictionary]? = nil
do
{
jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) as? [NSDictionary]
}
catch
{
throw(error)
}
return jsonDict
}
Response of API, when hit in browser is as:
Please help me, what i am doing wrong. Thanks.
UPDATE:
I just checked that if i convert data to String, it gives correct value. i.e.
let string = NSString(data: jsonData, encoding: NSASCIIStringEncoding)
print (string)
//OUTPUT: Optional({"Authenticated":true,"CustomerID":000,"CustomerName":"TEMP","Members":[{"MemberID":000,"MemberNumber":"000","MembershipID":00,"MembershipExpiration":"\/Date(1517464799000-0600)\/","ValidBuyerTypes":[0]}]})
Look at your code where you decode the JSON and the as? statement. You are trying to get an array of NSDictionary. Your JSON as printed contains a single dictionary, not an array.
This looks right to me. The only thing I can think is that (despite what the string output looks like) the top level container of your response is NOT an NSDictionary. In your jsonFromData function, instead of assuming the result of JSONObjecWithData will be an NSDictionary, I would say:
let iDunnoWhatThisIs = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) // don't cast this to NSDictionary
and see what you get back. It should either be a dictionary or an array, however, since you have NSJSONReadingOptions.AllowFragments set for the options, it's possible that it could be something else entirely. Start with making SURE you're actually getting back what you're assuming you are and go from there.
Try using NSKeyedUnarchiver instead:
jsonDict = NSKeyedUnarchiver.unarchiveObjectWithData(jsonData)! as NSDictionary

Resources