Exceptions and Error Handling
RemObjects Swift combines the error handling syntax, available since Swift 2.0, with the handling of real platform Exceptions.
Both error and exception handling is done with the do
/catch
keyword combination, and cleanup code (the traditional finally
block of exception handling) are performed with an independent defer
statement.
-
do
/catch
work pretty much as exception handling works in the other languages – the code inside thedo
scope is protected against failures, and one or morecatch
clauses can be provided where execution will continue if an exception or error occurs. Separatecatch
clauses can be defined to catch different kinds of errors, by class, or by more complex Pattern. -
defer
blocks can be used to specify code that will run at the end of the current scope, regardless of whether an error or exception occurred, or whether the method exited prematurely via a simplereturn
. This makesdefer
statements incredibly useful even when error handling is not involved.
Exceptions vs. Errors
The do
/catch
syntax combines handling of both errors (a concept which does not translate to the other platforms/languages) and exceptions in the following ways.
Exceptions
RemObjects Swift uses the regular do
/catch
syntax to protect code against exceptions, and executes the closest matching catch
block when an exception occurs. Keywords aside, this is no different than regular try
/catch
or try
/except
blocks in C# or Oxygene.
If no variable is provided for the catch
block, a default error
variable will be in scope, containing the current exception. It can be re-thrown with the throw
keyword.
Note that the try
(or try!
) keyword is not used or necessary for exception handling. It can be specified and will be ignored. This is because any statement can, potentially, throw an exception, and making every statement require a try
would be cluttery.
do {
let x = Int32.Parse("Five");
} catch {
println("could not parse string, failed with \(error)")
}
Errors
In addition, the try
or try!
keywords can be used inside the do
scope to call methods that follow Cocoa's and Swift's pattern of returning an Error
or NSError
value, explicitly or by being declared with throws
in Swift.
When called with the try
keyword, these methods drop the last Error
parameter, and their result is converted to be non-nullable (for functions that return a nullable value) or to be void
(for functions that return a Boolean
). When the function call returns nil
or false
, the remainder of the do
scope will be skipped, and execution will continue with the closest matching catch
clause for the received NSError
. No actual platform exception will be raised.
These methods can also be called the "old fashioned" way, without the try
keyword, and handling the return value and any returned error value will be up to the calling code (just as it would be from other languages). The calls will then not participate in any error handling logic provided by a potential do
/catch
.
do {
try NSFileManager.defaultManager.contentsOfDirectoryAtPath(path)
} catch {
println("could not read directory, failed with \(error)")
}
vs.
var error: NSError?
if !NSFileManager.defaultManager.contentsOfDirectoryAtPath(path, error: &error) {
println("could not read directory, failed with \(error)")
}
The NSError
Pattern
Exceptions can happen on all platforms (including Cocoa). Errors are limited to three specific scenarios:
- Methods that return a nullable result value and a nullable
__out NSError
value as last parameter, on Cocoa. - Methods that return a
Bool
result value and a nullable__out NSError
value as last parameter, on Cocoa. - Methods declared in Swift, using the
throw
keyword.
try?
The try?
syntax is also fully supported, for both exceptions and errors, and will convert any exception or error into a nil
value:
let x = try? Int32.Parse("Five");
//x will be nil
Converting Errors to Exceptions
RemObjects Swift also allows you to use the try
or try!
keywords to make calls to methods that follow the NSError
pattern, without a do
/catch
clause. If the method containing the try!
statement itself follows the NSError
pattern, any error received will be passed on to the caller of the current method. If the method does not follow the pattern, any error will be wrapped in a platform exception and thrown up the call stack.
Once again, try?
will catch errors and convert them into a nil result.
func countFilesInDirectory() -> Int throws {
let files = try! NSFileManager.defaultManager.contentsOfDirectoryAtPath(path)
return files.count
}
Throwing Errors and Exceptions
The throw
keyword can be used to throw an Exception (all methods) or an Error (inside methods that follow the NSError
Pattern).
Legacy Exception Handling Language Extension
Note that the temporary Exception Handling Language Extension we provided for Swift 1.0, using __try
, __finally
and __catch
, has been deprecated as of Elements version 8.2, and will be removed in a future update.
See Also
- Exception Handling, in Concepts
Exception
base class- Legacy
__try
/__finally
/__catch
language extension