-1

My Swift program is crashing, to handle the crash is their any way, i tried Exception handling i didn't got it, Does swift 4 supports Exception handling, what i want to do is i don't want my app to be crashed

here is the code i want to catch when ever i don't got the price value

let srt = self.Coin[indexPath.row] as! NSDictionary
var sr2=NSDictionary()
var barr  = NSArray()

if srt.value(forKey: "Price") != nil{
    do{
        barr = try srt.value(forKey: "Price") as! NSArray
        if (barr.count>0) {
            sr2 = barr[0] as! NSDictionary
        }
    } catch {
        print("Price is empty")
    }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
gopi
  • 25
  • 3
  • `if let barr = srt.value(forKey: "Price") as? NSArray { ... }` might be a safer bet – MadProgrammer Jun 12 '18 at 11:49
  • 2
    `Does swift 4 supports Exception handling` No. But it supports Do-Try-Catch for errors (not exceptions). Read the Swift ebook, everything is explained. – Eric Aya Jun 12 '18 at 11:55
  • 2
    Related: [Uncaught Error/Exception Handling in Swift](https://stackoverflow.com/q/38737880/1187415) – Martin R Jun 12 '18 at 12:08
  • Another option is of course to avoid possible runtime errors by **not** doing forced unwrapping and forced casting even if it means having to write one or two extra lines of code. – Joakim Danielson Jun 12 '18 at 12:19

2 Answers2

1

Not all errors can be caught in Swift. do-catch blocks can only handle errors thrown by throwable functions, whose declarations are marked using the throws keyword and errors that are explicitly thrown from inside those functions using the throw keyword.

All other errors in Swift are uncatchable, especially runtime errors caused by force unwrapping, force casting or force try (try!). When you use ! to force something, you tell the compiler that you know what you are doing and that a runtime error should be thrown in case an error occurs.

You shouldn't use force unwrapping/casting unless you are absolutely sure they won't fail or if you want to catch programming errors early in the development stage. Instead of using useless do-catch blocks with nested forced statements, simply use optional binding to safely cast/unwrap optional values.

Moreover, don't use NSDictionary and NSArray in Swift, use their native equivalents, Dictionary and Array. It seems like you are parsing JSON, so use [String:Any] instead of NSDictionary and [[String:Any]] instead of NSArray.

if let srt = self.Coin[indexPath.row] as? [String:Any] {
    if let barrs = srt["Price"] as? [[String:Any]], let barr = barrs.first {
    let sr2 = barr
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
0

As David said, I'd avoid force unwrapping and force casting. But instead of an if let statement, I'd rather use a guard let in order to avoid the pyramid of doom, like this:

 guard let srt = self.Coin[indexPath.row] as? [String:Any], let barr = srt["Price"] as? [[String:Any]], let sr2 = barr.first as? [String:Any] else {
        print("Price is empty")
        //Need to return, throw or whatever
    }

And we can even remove your intermediate variables, but it's much less readable, like so:

 guard let sr2 = ((self.Coin[indexPath.row] as? [String : Any])?["Price"] as? [[String : Any]])?.first as? [String : Any] else {
        print("Price is empty")
        //Need to return, throw or whatever
    }

If you'd rather go with the if let statement (in case you don't want to return or throw in your guard statement's else clause) you can also do it with a single if statement, like that

 if let srt = self.Coin[indexPath.row] as? [String:Any], let barr = srt["Price"] as? [[String:Any]], let sr2 = barr.first {
        //Do something with sr2
    }

And a shorter version without intermediate variables:

if let sr2 = ((self.Coin[indexPath.row] as? [String:Any])?["Price"] as? [[String:Any]])?.first {
        //Do something with sr2
    }

Whatever you choose... Don't force unwrap. Don't force try. Don't force cast. It will come back to bite you some day.

ElFitz
  • 908
  • 1
  • 8
  • 26