When a function or initializer is executed, there's a possibility of "throwing" an exception or error. It's important not to confuse this with the return value of a function.
To "enable" any of our functions or initializers to throw an error it must be marked with the throws
keyword. Then we can throw an error using the throw
keyword.
Let's imagine we have a function called showMessage
that takes a String
parameter, displays that parameter in the console, and returns the String
"OK". However, if the message is empty, it will throw a generic system error.
func showMessage(message: String) throws -> String {
if message.isEmpty {
throw NSError()
}
print(message)
return "OK"
}
The keyword throw
has the same effect as return
, the function or init will finish at that point.
Calling our function
Setting our function as throws
, changes the way to call it. Now we need to add try
before the function's name.
try showMessage(message: "My message")
But since thowing an error will cause a crash, we need to "catch" that error:
do {
let result = try showMessage(message: "My message")
print(result)
}
catch let error {
print(error)
}
// The console shows: OK
The code block defined as do
will be executed if there is no error, otherwise the code will stop at that point and the block defined as catch
will execute having that error as a variable.
Optional try
You can use try?
instead of do/catch
. This will return the result as optional, and a nil
value in case there is an error.
let result = try? showMessage(message: "My message")
print(result)
// The console shows: Optional("OK")
You can use if let
as well, just like any other Optional
.
if let result = try? showMessage(message: "My message") {
// Your code here
}
Throws in initializers
Initializers can be also be marked as throws
. It works in the same way.
class Person {
let name: String
init(name: String) throws {
if name.isEmpty {
throw NSError()
}
self.name = name
}
}
// Option with Do-Catch
do {
let client = try Person(name: "Pedro")
print(client.name)
}
catch let error {
print(error)
}
// Option with Optional
let client = try? Person(name: "Pedro")
print(client?.name)
Creating our own error types
We can create our own error types using enums and the Error protocol. This could provide a better description of what's the issue.
enum MyCustomError: Error {
case emptyMessage
case tooLongMessage
}
func showMessage(message: String) throws -> String {
if message.isEmpty {
throw MyCustomError.emptyMessage
}
else if message.count > 100 {
throw MyCustomError.tooLongMessage
}
print(message)
return "OK"
}
do {
let result = try showMessage(message: "My message")
print(result)
}
catch let error as MyCustomError {
print(error)
}
Be the first to comment