-
Swift’s
throw
/try
/catch
is designed for predictable, recoverable errors. -
Swift requires explicit syntax:
func foo() throws
try foo()
do { try foo() } catch { ... }
-
Errors must conform to
Error
protocol (typically enums). -
Swift errors don't unwind the stack unpredictably like exceptions in some languages.
-
No
finally
block, encouraging use ofdefer
instead.
- Exceptions often include both recoverable and unrecoverable errors (e.g., null dereferences).
- Exception types can be caught at runtime based on inheritance hierarchy.
- Exception handling is often lazy or optional, leading to silent error swallowing.
-
Catching and ignoring all errors:
do { try someFunction() } catch { // silently ignored }
❌ Hides bugs and prevents recovery logic.
-
Using exceptions for control flow:
- Overusing
throw
for non-exceptional cases (e.g., to signal end-of-loop). ❌ Makes code harder to follow and debug.
- Overusing
-
Catching too broadly:
catch { // Catches everything, even things you shouldn't handle here. }
-
Overuse of generic error enums with no actionable info:
enum MyError: Error { case unknown }
-
Use
Error
enums with associated values:enum NetworkError: Error { case badURL(String) case timeout(seconds: Int) case unauthorized }
-
Use
do
/try
/catch
narrowly:- Catch specific cases and recover meaningfully.
do { try fetchData() } catch NetworkError.timeout(let seconds) { retry(after: seconds) }
-
Avoid error swallowing — always log or handle intentionally:
catch { logger.error("Failed to fetch data: \(error)") }
-
Leverage
Result
type for deferred error handling:func loadImage() -> Result<Image, ImageError>
-
Use
try?
ortry!
only when safe or explicitly handled:try?
converts to optional: good for fallback logic.try!
crashes if an error is thrown: use only when you're absolutely certain.
-
Use Swift Concurrency’s
async throws
idiomatically:func fetchUser() async throws -> User
- Call sites use
try await
to clearly show suspension and error risk.
- Call sites use
Concept | Swift | Other Languages (e.g., Java) |
---|---|---|
Terminology | "Error", throw |
"Exception", throw |
Checked/Unchecked | All errors are explicit | Often mixed or unchecked |
Type system integration | Uses Error conforming types |
Often built-in exception hierarchy |
Preferred usage | Predictable failure paths | Both predictable and crash-like |
Recovery mechanism | do / try / catch |
try / catch / finally |
Swift encourages clarity and safety, making error handling composable, explicit, and recoverable — not as an afterthought, but as a first-class part of control flow.