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]
}
} ...
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 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)
}
If server response is (result = "Account Exists") then i can do something. but when i compare the result it gives an error that "Binary operator '==' cannot be applied to operands of type 'Any' and 'String'".
let dataTask = session.dataTask(with: url!, completionHandler: { (data, response, error) -> Void in
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSDictionary
print("JSON : \(json)")
if let dataDic = json.value(forKey: "data")
{
print("dataDic: \(dataDic)")
if let Result = (dataDic as AnyObject).value(forKey: "Result")
{
print("Result: \(Result)")
if (Result ("Account Exists")) == 0
{
//... DO Something
}
}
}
}
catch
{
print("Catch exception")
}
})
dataTask.resume()
}
In pure swift way .. your "data" is an array and Top level json is Dictionary
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
if let data = json["data"] as? [[String:String]] {
if let resultString = data.first?["Result"] as? String{
if resultString == "Account Exists"{
//... DO Something
}
else if resultString == "Unauthorized Access" {
//... DO Something
}
}
}
}
catch{
print("Catch exception")
}
please update below in your code and check it
if (Result ("Account Exists") as! String) == "0"
{
//... DO Something
}
If your Result is a string, you need to unwrap it accordingly and then compare, you can implement the comparing while unwrapping itself, you can do something like
if let Result = (dataDic as AnyObject).value(forKey: "Result") as? String, Result == "Unauthorized Access"
{
print("Result: \(Result)")
// DO whatever you want here in case of Unauthorised access
}
Can't access json object which is array inside json object
i want to access data from json object which have array inside array
and that json file is also uploaded
so pls can anyone check and help me how to get "weather.description"
data
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=13ae70c6aefa867c44962edc13f94404")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("some error occured")
} else {
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
let newValue = jsonResult as! NSDictionary
print(jsonResult)
let name = newValue["name"]
//Here i am getting name as variable value
//this is not working
let description = newValue["weather"]??[0]["description"]
//this is not working
let description = newValue["weather"]!![0]["description"]
print()
}catch {
print("JSON Preocessing failed")
}
}
}
}
task.resume()
}
I have edited your code a bit, and added a few comments. Basiclly, lets check for the types of your response structure, and get the desired value.
let url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=13ae70c6aefa867c44962edc13f94404")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("some error occured")
} else {
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
// I would not recommend to use NSDictionary, try using Swift types instead
guard let newValue = jsonResult as? [String: Any] else {
print("invalid format")
return
}
// Check for the weather parameter as an array of dictionaries and than excess the first array's description
if let weather = newValue["weather"] as? [[String: Any]], let description = weather.first?["description"] as? String {
print(description)
}
}catch {
print("JSON Preocessing failed")
}
}
}
}
task.resume()
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
let arrayJSON = resultJSON as! NSArray
let success:NSInteger = arrayJSON["success"] as! NSInteger
if (success == 1 ) ....
json data is the response from the server, i am trying to convert it to integer but i get the conversation error.
This is a working exmaple (tested on my machine)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let data = data{
print("data =\(data)")
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
let resultDictionary = resultJSON as? NSDictionary
let success = resultDictionary!["success"]!
let successInteger = success as! Int
print("success = \(success)")
if successInteger == 1 {
print("yes")
}else{
print("no")
}
}catch _{
print("Received not-well-formatted JSON")
}
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
where the response is:
{ "error_message" : "No User", "success" : 0}
Note
you said that your server responnes as:
{ "error_message" = "No User"; success = 0; }
and this is not a valid json, you should correct it to match the json that i gave to you
You're casting resultJSON as an NSArray but then you try to use it as a dictionary by subscripting "success".
If the response is a dictionary, then cast the result as a dictionary:
let result = resultJSON as! NSDictionary
let success = result["success"] as! NSInteger
If the response is an array of dictionaries, then first select one of the items before subscripting.
let arrayJSON = resultJSON as! NSArray
let success = arrayJSON[0]["success"] as! NSInteger
Note: when possible, prefer using Swift's typed arrays an dictionaries rather than Foundation's NSArray and NSDictionary. Also you should avoid force casting with !, it's better to unwrap optionals safely with if let ... = ... as? ... or any other mechanism.
Update
Here's an example:
do {
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
var success = 0
if let dictJSON = resultJSON as? [String:AnyObject] {
if let successInteger = dictJSON["success"] as? Int {
success = successInteger
} else {
print("no 'success' key in the dictionary, or 'success' was not compatible with Int")
}
} else {
print("unknown JSON problem")
}
if success == 1 {
// yay!
} else {
// nope
}
In this example I'm using a Swift dictionary [String:AnyObject] instead of an NSDictionary, and I'm using a Swift integer Int instead of Foundation's NSInteger. I'm also typecasting with if let instead of forcing.