how to avail the catch concept in swift 2.0 - ios

I just converted my code to Swift 2.0 and it converted the code beautifully.
Just one thing I am not able to understand that how to use the try-catch in my codes.
I am posting the data and getting the JSON formatted
if anything goes wrong in network then it throws error and app crashes when JSON serialisation is done. How to prevent this, my code snap is below.
do {
json = try! NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
}
catch {
// report error
}
It crashed in the line
json = try! NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
How to use catch so that it does not crash here and shows error!!!

I'm using it in my project like
do{
if let result = try NSJSONSerialization.JSONObjectWithData(resultData, options: []) as? NSMutableDictionary{
}
}
catch let error as NSError{
print("Error : \(error)")
}

use this syntax, and remove the "!" in the try
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
}
catch _ {
// report error
print("Exception")
}

like diego said but the catch do like this to see what is the error you get in case you get one for debugging
catch let error as NSError{
print("Error : \(error)")
//or NSLog()
NSLog("Error = %#",error)
}

Related

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)
}

Swift iOS NSJsonSerialization fails silently

I have the following code fetching json data via an API.
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
// print("Response: \(response)")
// print("DATA: \(data)")
if data != nil {
do {
print( NSString(data: data!, encoding: NSUTF8StringEncoding))
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray {
print("\n\nThe return JSON looks like this: \(jsonResults)\n\n")
}
} catch {
print("\n\nProblem getting JSON back from GET API.\n\n")
}
} else {
print("API Not Available") // data was nil
}
}) // task
task.resume()
The "print" of the NSString shows what to my eyes looks like valid JSON. The console shows this as:
Optional({"id":15,"user_id":11,"breed_id":593,"gender":"Male","age_years":5,"tally":{"count":1246,"struvite":716,"calcium_oxalate":388,"urate":217,"calcium_phosphate":30,"silica":21,"compound":41},"created_at":"2016-02-04T08:26:14.719-06:00","updated_at":"2016-02-04T08:26:14.719-06:00"})
However, the "if let jsonResults =" statement does execute successfully (there is no jsonResults printed) and the catch does not execute either -- so it seems like a silent error.
A very similar call works on another part of the API. The only big difference is that "tally" in the JSON return on this call is nested.
Any suggestions are appreciated.
The JSON may not be serialised properly, so try to replace:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
with:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [String: AnyObject]
let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSMutableDictionary
This implementation is a lot neater, and you don't have to specify their data types.
The answer was a combination of dzk and ishaq's responses.
I replaced
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
with:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
The essential piece was casting it as a Dictionary, not an Array.

Crash while casting the result of JSONObjectWithData to Dictionary<String,Any>

The Application crashes while parsing JSON result to <String,Any> it does not enters the catch block:
do
{
result = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! Dictionary<String,Any>
}
catch let error1 as NSError
{
result = nil
print(error1)
}
While if I casted the JSON result to <String,AnyObject> it works fine:
do
{
result = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! Dictionary<String,AnyObject>
}
catch let error1 as NSError
{
result = nil
print(error1)
}
Is not the <Any> protocol accepts both the primitive types and the object types , then why it's failing ?
The reason you are crashing is the forced cast you are making. The do / catch construct in Swift doesn't work like exceptions in other languages, where any error will be caught in the catch block. In your case
NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
can throw an error, and the catch block will be called if an error is thrown. In contrast the forced cast to Dictionary does not throw an error if it fails. It would be far better to wrap the cast in an if let like so:
do
{
let temp = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
if let result = temp as? Dictionary<String,AnyObject> {
// Do something with the result
}
else {
// cast failed handle it gracefully
}
}
catch let error1 as NSError
{
result = nil
print(error1)
}
Now as to why the cast to "String, AnyObject" works while "String, Any" fails, I suspect it has to do with the fact that originally, it is an NSDictionary being returned from your JSON call. Those are bridged to Swift Dictionaries as "String, AnyObject". Now, what you are trying to do should technically work, and I consider it a bug that it doesn't. You might consider filing a radar for this behavior. In the meantime, it would also be advisable to avoid force casting as much as possible.
Don't use Any.
AnyObject covers all types JSON supports.

Issue with Swift 2 Error Handling

I am using REST to get JSON data and then parse it. To do this I am using NSJSONObjectWithData, as far as I'm aware this method used to have an error handler within its parameters but it's no longer there. In my code here:
let err: NSError?
let options:NSJSONReadingOptions = NSJSONReadingOptions.MutableContainers
var jsonResult = NSJSONSerialization.JSONObjectWithData(data!, options: options) as! NSDictionary;
I get an error which says:
"Call can throw, but it is not marked with 'try' and the error is not handled"
How would I go about fixing this error?
Here is the correct implementation,
do {
let jsonDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
//Use your dictionary here.
print("JSON : \(jsonDictionary)")
}
catch {
print(error)
//Handle any error.
}

Swift: Extra argument 'error' in call

I'm currently developing my first iOS app using Swift 2.0 and Xcode Beta 2. It reads an external JSON and generates a list in a table view with the data. However, I'm getting a strange little error that I can't seem to fix:
Extra argument 'error' in call
Here is a snippet of my code:
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
print("Task completed")
if(error != nil){
print(error!.localizedDescription)
}
var err: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary{
if(err != nil){
print("JSON Error \(err!.localizedDescription)")
}
if let results: NSArray = jsonResult["results"] as? NSArray{
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.appsTableView!.reloadData()
})
}
}
})
The error is thrown at this line:
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary{
Can someone please tell me what I'm doing wrong here?
With Swift 2, the signature for NSJSONSerialization has changed, to conform to the new error handling system.
Here's an example of how to use it:
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
print(jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
With Swift 3, the name of NSJSONSerialization and its methods have changed, according to the Swift API Design Guidelines.
Here's the same example:
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject] {
print(jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
Things have changed in Swift 2, methods that accepted an error parameter were transformed into methods that throw that error instead of returning it via an inout parameter. By looking at the Apple documentation:
HANDLING ERRORS IN SWIFT:
In Swift, this method returns a nonoptional result and is marked with the throws keyword to indicate that it throws an error in cases of failure.
You call this method in a try expression and handle any errors in the catch clauses of a do statement, as described in Error Handling in The Swift Programming Language (Swift 2.1) and Error Handling in Using Swift with Cocoa and Objective-C (Swift 2.1).
The shortest solution would be to use try? which returns nil if an error occurs:
let message = try? NSJSONSerialization.JSONObjectWithData(receivedData, options:.AllowFragments)
if let dict = message as? NSDictionary {
// ... process the data
}
If you're also interested into the error, you can use a do/catch:
do {
let message = try NSJSONSerialization.JSONObjectWithData(receivedData, options:.AllowFragments)
if let dict = message as? NSDictionary {
// ... process the data
}
} catch let error as NSError {
print("An error occurred: \(error)")
}
This has been changed in Swift 3.0.
do{
if let responseObj = try JSONSerialization.jsonObject(with: results, options: .allowFragments) as? NSDictionary{
if JSONSerialization.isValidJSONObject(responseObj){
//Do your stuff here
}
else{
//Handle error
}
}
else{
//Do your stuff here
}
}
catch let error as NSError {
print("An error occurred: \(error)") }

Resources