I've run into this silly behaviour in swift where force-unwrapping an optional does not propagate.
From the documentation:
Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.
To reproduce:
func foo(bar:String?) throws{
print(bar!);
}
And
try foo(nil);
This does not seem logical or consistent to me and I can't find any documentation on this subject.
Is this by design?
From the documentation:
Error Handling
Error handling is the process of responding to and recovering from error conditions in your program. Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime.
...
Representing and Throwing Errors
In Swift, errors are represented by values of types that conform to the
ErrorType
protocol. This empty protocol indicates that a type can be used for error handling.
(Note: ErrorType
has been renamed to Error
in Swift 3)
So with try/catch
you handle Swift errors (values of types that conform to the ErrorType
protocol) which are throw
n.
This is completely unrelated to runtime errors and runtime exceptions
(and also unrelated to NSException
from the Foundation library).
Note that the Swift documentation on error handling does not even use the word "exception", with the only exception (!) in (emphasis mine) in:
NOTE
Error handling in Swift resembles exception handling in other languages, with the use of the try, catch and throw keywords. Unlike exception handling in many languages—including Objective-C—error handling in Swift does not involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement.
The unwrapping of optionals which are nil
does not throw
a
Swift error (which could be propagated) and cannot be handled with
try
.
You have to use the well-known techniques like
optional binding, optional chaining, checking against nil
etc.
this 'self explanatory' example can help you to see the difference between raising an runtime exception and throwing an error E conforming to ErrorType protocol.
struct E: ErrorType{}
func foo(bar:String?) throws {
if let error = bar where error == "error" {
throw E()
}
print(bar, "is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil)")
// here is everything OK
let bar = bar!
// but here it crash!!
_ = bar.characters
}
do {
try foo("error")
// next line is not accessible here ...
try foo(nil)
} catch {
print("\"error\" as parameter of foo() throws an ERROR!")
}
do {
try foo(nil) // fatal error: unexpectedly found nil while unwrapping an Optional value
} catch {
}
it prints
"error" as parameter of foo() throws an ERROR!
nil is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil)
fatal error: unexpectedly found nil while unwrapping an Optional value
raising an runtime exception is fatal error in your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With