-
Swift’s
throw/try/catchis designed for predictable, recoverable errors. -
Swift requires explicit syntax:
func foo() throwstry foo()do { try foo() } catch { ... }
-
Errors must conform to
Errorprotocol (typically enums). -
Swift errors don't unwind the stack unpredictably like exceptions in some languages.
-
No
finallyblock, encouraging use ofdeferinstead.
- 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
throwfor 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
Errorenums with associated values:enum NetworkError: Error { case badURL(String) case timeout(seconds: Int) case unauthorized }
-
Use
do/try/catchnarrowly:- 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
Resulttype 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 throwsidiomatically:func fetchUser() async throws -> User
- Call sites use
try awaitto 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.