Swift Errors
Table of contents
Here's an explanation of syntax errors, runtime errors and error handling in Swift:
Syntax Errors:
These are errors that occur when the code does not follow the rules of the programming language.
The code will not compile due to syntax errors.
Examples: missing a semicolon, using incorrect brackets, misspelling a keyword etc.
Runtime Errors:
These errors occur when the code is running/executing.
The code compiles fine but crashes at runtime due to an error.
Examples: accessing an array out of bounds, dividing by zero, force unwrapping an optional that is nil etc.
Error Handling:
- Define custom error types using enums:
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
- Throw errors from functions using
throw
:
func makeSelection(selection: Int) throws {
...
if selection < 1 || selection > 9 {
throw VendingMachineError.invalidSelection
}
...
}
- Catch errors using
do - catch
:
do {
try makeSelection(selection: 5)
} catch VendingMachineError.invalidSelection {
print("Invalid selection.")
} catch {
print("Unexpected error: \(error)")
}
- Use a catch-all case to catch any unexpected errors.
The strategy is to define meaningful, custom error types for expected errors and have a catch-all case to handle any unexpected runtime errors.
Proactive Programming
Preventing errors from happening in the first place is better than reacting to errors after they occur. Here are some ways to use proactive coding to prevent errors:
- Use assertions: Assertions allow you to verify assumptions about your code, and crash if the assertion fails. This helps catch bugs earlier. For example:
assert(name.count > 2, "Name should be at least 3 characters long")
If name
has less than 3 characters, the assertion will fail and crash the program, alerting you to fix the input validation earlier.
- Validate input before using it: Instead of force unwrapping optionals or accessing arrays out of bounds, validate any user input before using it. For example:
guard name.count > 2 else {
// Show error
return
}
- Define preconditions and postconditions: These are similar to assertions, but used to define the valid state of a function before and after it executes. For example:
precondition(age > 0, "Age must be greater than 0")
// Function code
postcondition(result != nil, "Result should not be nil")
- Use protocol extensions to define default behavior: This reduces the chance of implementing a method incorrectly.
So in summary, using assertions, input validation, pre/post-conditions and protocol extensions can help prevent many errors from happening in the first place. Try/catch is still useful for unexpected runtime errors, but the proactive techniques allow you to catch bugs earlier and write more robust code.
Disclaim: I'm learning Swift using AI. These are my notes. I ask questions so you don't have to. If you have comments, do not hesitate to post. I like some feedback.
Subscribe to my newsletter
Read articles from Elucian Moise directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Elucian Moise
Elucian Moise
Software engineer instructor, software developer and community leader. Computer enthusiast and experienced programmer. Born in Romania, living in US.