Error handling is a crucial part of programming, and Swift provides multiple ways to deal with potential failures. Many beginners struggle to understand why <span class="text-color-code"> do-try-catch </span>
exists when we already have other mechanisms like Optionals, Tuples, and Result enums.
In this blog, we’ll go step by step, analyzing different error-handling approaches and showing why <span class="text-color-code"> do-try-catch </span>
is the cleanest and most structured way to handle errors in Swift.
Step 1: Understanding the Problem — <span class="text-color-code"> isActive </span>
Flag
We will use a class called <span class="text-color-code"> DoTryCatchDataManager </span>
, which has a flag <span class="text-color-code"> isActive </span>
.
- If
<span class="text-color-code"> isActive = true </span>
, it returns valid data. - If <span class="text-color-code"> isActive = false </span>, it simulates a failure, returning either <span class="text-color-code"> nil </span>, an error, or throwing an error.
Function 1: Using Optionals (<span class="text-color-code">getTitle1()</span>
)
func getTitle1() -> String? {
if isActive {
return "Title 1"
} else {
return nil // No title if isActive is false
}
}
Problem with Optionals
This function returns an Optional String (<span class="text-color-code">String?</span>
), which means:
- If
<span class="text-color-code"> isActive = true </span>
, it returns<span class="text-color-code"> "Title 1" </span>
. - If
<span class="text-color-code"> isActive = false </span>
, it returns<span class="text-color-code"> nil </span>
.
How Do We Handle This?
To use this function safely, we need optional unwrapping (<span class="text-color-code"> if let </span>
, <span class="text-color-code"> guard let </span>
, or <span class="text-color-code"> ?? </span>
operator).
Example:
let title = getTitle1() ?? "Error: No Title"
What’s Wrong with This Approach?
❌ It doesn’t tell us why it failed. We just get <span class="text-color-code"> nil </span>
, but we don’t know what went wrong.
❌ Forces developers to unwrap the optional. Beginners often forget to handle <span class="text-color-code"> nil </span>
, which leads to unexpected crashes.
Function 2: Using Tuples (<span class="text-color-code">getTitleTitle2()</span>
)
func getTitleTitle2() -> (title: String?, error: Error?) {
if isActive {
return ("Title 2", nil)
} else {
return (nil, URLError(.badURL)) // Simulating error
}
}
What Changed?
Now, the function returns a tuple:
<span class="text-color-code"> title: String? </span>
→ The actual value (if successful).<span class="text-color-code"> error: Error? </span>
→ The error (if something goes wrong).
How Do We Handle This?
We need to manually check both values:
let result = getTitleTitle2()
if let title = result.title {
print("Success: \(title)")
} else {
print("Error: \(result.error?.localizedDescription ?? "Unknown Error")")
}
What’s Wrong with This Approach?
❌ Still requires manual error checking. We need to handle both the <span class="text-color-code"> title </span>
and <span class="text-color-code"> error </span>
manually.
❌ Not Swift-like. It feels like we are simulating an error-handling system instead of using Swift’s built-in error-handling mechanism.
Function 3: Using <span class="text-color-code"> Result
</span> Enum (<span class="text-color-code">getTitle3()
</span>)
func getTitle3() -> Result<String, Error> {
if isActive {
return .success("Title 3")
} else {
return .failure(URLError(.badURL)) // Simulating failure
}
}
What Changed?
This function now returns Swift’s built-in <span class="text-color-code"> Result </span> type, which can either be:
<span class="text-color-code"> .success(value) </span>
→ Contains the title.<span class="text-color-code"> .failure(error) </span>
→ Contains the error.
How Do We Handle This?
We use a switch case:
switch getTitle3() {
case .success(let title):
print("Success: \(title)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
What’s Wrong with This Approach?
✅ Better than Optionals & Tuples because it forces us to handle both success and failure.
❌ Still requires a switch case. The error-handling logic is separated from where the function is called.
❌ Becomes complex when dealing with multiple function calls. Imagine handling five functions this way — our code would become messy with <span class="text-color-code"> switch </span> cases everywhere.
Function 4: Using <span class="text-color-code"> do-try-catch
</span> (<span class="text-color-code">getTitle4()
</span>)
func getTitle4() throws -> String {
if isActive {
return "Title 4"
} else {
throw URLError(.badURL)
}
}
What Changed?
- Instead of returning <span class="text-color-code"> nil </span>, a tuple, or a <span class="text-color-code"> Result </span>, this function throws an error if something goes wrong.
- This means Swift enforces error handling.
How Do We Handle This?
We must use <span class="text-color-code"> do-try-catch </span>:
do {
let title = try getTitle4()
print("Success: \(title)")
} catch {
print("Error: \(error.localizedDescription)")
}
Why <span class="text-color-code"> do-try-catch </span> is the Best Approach?
✅ Forces error handling. Unlike Optionals, we cannot ignore the error.
✅ No unnecessary <span class="text-color-code"> switch case </span>. We just <span class="text-color-code"> try </span> the function and handle the error in <span class="text-color-code"> catch </span>.
✅ Easier to read & maintain. Swift’s built-in error handling mechanism keeps the code structured and clear.
Comparing All Four Approaches

Final Thoughts: When to Use What?

Conclusion: Why <span class="text-color-code"> do-try-catch </span> is Beautiful
- It forces error handling, so no errors are ignored.
- It keeps code clean, without messy <span class="text-color-code"> if let </span>, <span class="text-color-code"> switch </span>, or tuple checks.
- It uses Swift’s built-in error system, making it easy to integrate with other libraries.
By understanding why <span class="text-color-code"> do-try-catch </span> exists, beginners can appreciate how Swift encourages safer and more structured error handling.
Feel free to drop your thoughts and comments on my Medium blog here and for any project related inquiries, contact us below.
Send us a quick query
Recommended Posts

The Ultimate Guide to Choosing the Best Wireframing Tools for Product Managers

Efficient Caching Techniques in iOS: From Beginner to Advanced
