I believe that the jsonArray["success"] is returning to me that it is nil. because when I ran it without the if case it returned that it was nil. But I don't get why its doing that when there is data in the array
if let data = data {
print(String(data: data, encoding: .utf8) ?? "")
do {
if let jsonArray = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]{
print(jsonArray)
if let success = jsonArray["success"] as? String {
print(jsonArray)
print(success) //BOOKMARK: Success displays that it is null....why?! 10-13-2017, 12:49
print("foo")
}
}
}
catch{
//TODO tell user something didnt work
print(error)
}
}
//handle reading all json
})
Below is what I received when the if case was not implemented:
{"success":0,"message":"User not found or wrong password"}
["message": User not found or wrong password, "success": 0]
nil
foo
Related
After decrypting my response from API i am getting a string "name:DM100, profile:[1,2,4,5]".
How can i convert this to a json object where name is string and profile is an array
i have tried using but getting nil
if let data = testString.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print("JSON Serialization Error :-> \(error.localizedDescription)")
}
}
return nil
}
Your JSON String is not valid. It should look like this:
let testString = "{\"name\":\"DM100\", \"profile\":[1,2,4,5]}"
if let data = testString.data(using: .utf8) {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print(json["name"])
}
}
catch {
print(error.localizedDescription)
}
}
Start and end with curly braces {} and have double quotations around string keys and values.
You can use following code to get the output:
But String must have and valid JSON format first as follows:
let string = "{\"name\":\"DM100\", \"profile\":[1,2,4,5]}"
let data = string.data(using: .utf8)!
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? Dictionary<String,Any> {
print(jsonObj)
} else {
print("JSON Error")
}
} catch let error as NSError {
print(error)
}
I send request like this:
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
// check for fundamental networking error
print("error=\(String(describing: error))")
completion(nil)
return
}
print("********_Respone status code is: ",(response as! HTTPURLResponse).statusCode)
print("********_Respone url code is: ",response?.url as Any )
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
let res:HTTPURLResponse = response as! HTTPURLResponse
print(json)// yessssssssss goooood
} catch {
completion(nil)
return
}
}
task.resume()
it's working correctly when response is a Dictionary, but when my response is an array show this error:
Could not cast value of type '__NSArrayI' to 'NSDictionary'
Please help me to fix this.
Deserialize the JSON once and omit the options, Array and Dictionary aren't fragmented. Then optional bind the result.
do {
let json = try JSONSerialization.jsonObject(with: data)
if let jsonArray = json as? [[String:Any]] {
print("json is array", jsonArray)
} else if let jsonDictionary = json as? [String:Any] {
print("json is dictionary", jsonDictionary)
} else {
print("This should never be displayed")
}
} ...
If the result is supposed to be only Array or Dictionary then you can force unwrap the result to dictionary and remove the last else clause
do {
let json = try JSONSerialization.jsonObject(with: data)
if let jsonArray = json as? [[String:Any]] {
print("json is array", jsonArray)
} else {
let jsonDictionary = json as! [String:Any]
}
} ...
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")
}
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)
}
The following lines of code are written inside a function and session_id and session_name are global variables.
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("dataString1 = \(dataString)")
var json = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
if(error != nil) {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
print(error)
}
else
if let parseJSON = json {
print("jsonstr = \(json)")
if let success = parseJSON["success"] as? String {
if success == "true" {
let session_valid = parseJSON["session_valid"] as! String
if session_valid == "true"{
let response = parseJSON.objectForKey("response") as! NSDictionary
print("response = \(response)")
session_id = response.objectForKey("session_id") as! String
session_name = response.objectForKey("session_name") as! String
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if let resultController = self.storyboard!.instantiateViewControllerWithIdentifier("splitViewController") as? UISplitViewController {
self.presentViewController(resultController, animated: true, completion: nil)
}
})
}
}
}
print("values1 are \(session_id) and \(session_name)") //print stmt 1
return
}//if
else {
print("json not parsed")
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
print(error)
}//else
}
print("values are \(session_id) and \(session_name)") //print stmt 2
task.resume()
The output relevant to the query is: (session_id and session_name are initialised to random values 1 and a)
values are 1 and a
and then it prints: (values of the two variables in the response from the php script)
values1 are ckj0uuj2q18m97m78m1uvje7f5 and d72d1363f44031cac4148b0e6fa295d6
My query is that how is 'print stmt 2' printed before 'print stmt 1'? I am new to swift. Am I missing any concept here?
Also, why does 'print stmt 2' print the initial values of the variables and not the new values? I know the two questions are related but I am not getting how
The code inside that big block (Swift calls it a closure) gets run after the request completes. There's not a way to get a value over the Internet immediately, because it can take up to 90 seconds, and you don't want your entire app blocked for that long (particularly because iOS will kill your app outright after 30).
The way you solve that is by changing the code that needs the values so that it provides code to run after the values have been retrieved, to do something with those values.
See https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html for more info.