0
0
iOS Swiftmobile~15 mins

Error handling for network calls in iOS Swift - Deep Dive

Choose your learning style9 modes available
Overview - Error handling for network calls
What is it?
Error handling for network calls means managing problems that happen when your app tries to get or send data over the internet. These problems can be things like no internet connection, server errors, or bad responses. Handling these errors well helps your app stay stable and tell users what went wrong. Without it, your app might crash or confuse users when network issues happen.
Why it matters
Network calls are often unreliable because the internet can be slow or disconnected. If your app does not handle errors properly, users may see crashes, frozen screens, or wrong information. Good error handling improves user trust and app quality by gracefully managing failures and giving clear feedback. Without it, apps feel broken and users may stop using them.
Where it fits
Before learning this, you should understand how to make basic network calls in Swift using URLSession. After mastering error handling, you can learn about advanced topics like retry strategies, caching, and offline support to make your app more resilient.
Mental Model
Core Idea
Error handling for network calls is about catching and managing problems that happen during internet communication to keep the app stable and user-friendly.
Think of it like...
It's like sending a letter through the mail: sometimes the letter gets lost, delayed, or returned. You need to check if it arrived and handle problems like lost mail so the message still gets through or you know what went wrong.
┌───────────────┐
│ Start network  │
│ request       │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Wait for      │
│ response      │
└──────┬────────┘
       │
       ▼
┌───────────────┐       ┌───────────────┐
│ Success       │──────▶│ Use data      │
│ (200 OK)      │       └───────────────┘
└───────────────┘
       │
       ▼
┌───────────────┐       ┌───────────────┐
│ Error         │──────▶│ Handle error  │
│ (timeout,     │       │ (show message,│
│ no internet)  │       │ retry, etc.)  │
└───────────────┘       └───────────────┘
Build-Up - 7 Steps
1
FoundationBasics of network call errors
🤔
Concept: Network calls can fail for many reasons like no internet or server problems.
When you make a network call with URLSession, the system returns data, response, and error. The error tells you if something went wrong, like no connection or timeout. You must check this error before using the data.
Result
You learn to detect if a network call failed and why.
Understanding that network calls can fail anytime helps you prepare your app to handle these failures gracefully.
2
FoundationUsing Swift's Result type for errors
🤔
Concept: Swift's Result type cleanly separates success and failure in asynchronous calls.
Instead of separate data and error parameters, use Result to represent success or failure. This makes your code clearer and safer by forcing you to handle both cases.
Result
Your network call functions return a Result that you can switch over to handle success or error.
Using Result improves code readability and ensures you never forget to handle errors.
3
IntermediateDistinguishing error types
🤔Before reading on: do you think all network errors are the same or different types? Commit to your answer.
Concept: Not all errors are equal; some are client issues, some server, some data format problems.
Errors can be URLSession errors (like no internet), HTTP errors (like 404 or 500 status codes), or decoding errors when parsing data. Handling each type differently improves user feedback and recovery.
Result
You can identify and respond to different error causes properly.
Knowing error types helps you give users accurate messages and decide when to retry or fail.
4
IntermediateShowing user-friendly error messages
🤔Before reading on: should error messages to users be technical or simple? Commit to your answer.
Concept: Users need clear, simple messages, not technical jargon.
Map technical errors to friendly messages like 'No internet connection' or 'Server is down, please try later'. Use UIAlertController or custom views to show these messages.
Result
Users understand what went wrong and what to do next.
Good error messages improve user experience and reduce frustration.
5
IntermediateRetrying failed network calls
🤔
Concept: Sometimes network calls fail temporarily and retrying can fix the problem.
Implement retry logic with limits and delays. For example, retry up to 3 times with increasing wait times. Avoid infinite retries to prevent app hangs.
Result
Your app can recover from temporary network glitches automatically.
Retrying smartly increases app reliability without annoying users.
6
AdvancedUsing Swift's async/await with error handling
🤔Before reading on: do you think async/await changes how you handle errors? Commit to your answer.
Concept: Async/await syntax simplifies asynchronous code and error handling.
With async/await, you call network functions using 'try await'. Errors are thrown and caught with do-catch blocks, making error handling more natural and readable.
Result
Your network code looks cleaner and error handling is integrated with Swift's error system.
Async/await aligns network error handling with Swift's native error model, reducing bugs and improving clarity.
7
ExpertHandling complex error scenarios in production
🤔Before reading on: do you think all network errors should be treated the same in production? Commit to your answer.
Concept: In real apps, error handling must consider offline mode, caching, and analytics.
Use reachability checks to detect offline status before calls. Cache data to show when offline. Log errors for analytics to improve backend. Use custom error types to represent app-specific issues.
Result
Your app handles errors robustly, improves over time, and provides offline support.
Advanced error handling integrates multiple systems to create a seamless user experience even when networks fail.
Under the Hood
When a network call is made, URLSession creates a task that runs asynchronously. The system manages the connection, waits for response, and then calls your completion handler with data, response, and error. The error parameter is non-nil if something went wrong at the system or network level. HTTP errors are not treated as errors by URLSession but must be checked by inspecting the response status code. Decoding errors happen when converting data to your model objects. Swift's error handling uses throwing functions and do-catch blocks to propagate and catch errors cleanly.
Why designed this way?
URLSession separates transport errors (like no connection) from HTTP errors to give developers control over how to handle different failure types. Swift's error handling model with throwing functions was designed to make error propagation explicit and safe, avoiding silent failures. This design balances flexibility with safety, allowing apps to respond appropriately to diverse network conditions.
┌───────────────┐
│ URLSession    │
│ creates task  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Network layer │
│ manages TCP   │
│ connection    │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Server sends  │
│ response      │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Completion    │
│ handler called│
│ with data,    │
│ response, err │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Swift error   │
│ handling with │
│ do-catch     │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: do you think a non-200 HTTP status code automatically triggers an error in URLSession? Commit to yes or no.
Common Belief:If the server returns a 404 or 500 status, URLSession treats it as an error and sets the error parameter.
Tap to reveal reality
Reality:URLSession does NOT treat HTTP status codes like 404 or 500 as errors. The error parameter is nil, and you must check the HTTPURLResponse status code yourself.
Why it matters:If you rely only on the error parameter, you might miss server errors and treat failed requests as successes, causing wrong app behavior.
Quick: do you think all network errors mean the user has no internet? Commit to yes or no.
Common Belief:Any network error means the device is offline or has no internet connection.
Tap to reveal reality
Reality:Network errors can be caused by many issues like server timeouts, DNS failures, or SSL problems, not just no internet.
Why it matters:Assuming all errors mean no internet can lead to wrong user messages and missed opportunities to retry or fix other issues.
Quick: do you think showing raw error messages to users is best? Commit to yes or no.
Common Belief:Showing the exact technical error message from the system helps users understand the problem.
Tap to reveal reality
Reality:Raw error messages are often confusing or scary to users. Friendly, simple messages improve user experience.
Why it matters:Technical messages can frustrate users and reduce app trust, leading to poor reviews or abandonment.
Quick: do you think retrying network calls infinitely is a good idea? Commit to yes or no.
Common Belief:If a network call fails, keep retrying until it succeeds to ensure data is fetched.
Tap to reveal reality
Reality:Infinite retries can freeze the app or drain battery. Retrying should have limits and delays.
Why it matters:Without limits, retries can cause poor app performance and bad user experience.
Expert Zone
1
Some network errors are transient and should be retried, while others are permanent and should fail fast; distinguishing these requires deep understanding of error codes.
2
Combining error handling with reachability checks can prevent unnecessary network calls when offline, saving resources and improving responsiveness.
3
Logging and analytics of network errors in production help identify backend issues and improve app stability over time.
When NOT to use
Simple error handling is not enough when building apps that must work offline or with flaky networks. In those cases, use caching, background sync, and offline-first architectures instead of relying solely on retrying network calls.
Production Patterns
In production, apps often wrap network calls in services that centralize error handling, map errors to user-friendly messages, implement exponential backoff retries, and integrate with monitoring tools to track error rates and user impact.
Connections
Exception handling in general programming
Error handling for network calls builds on the same principles of catching and managing exceptions or errors in code.
Understanding general exception handling helps grasp how network errors propagate and are caught in asynchronous calls.
User experience design
Error handling connects directly to UX by deciding how to communicate problems to users effectively.
Good error handling improves UX by providing clear, actionable feedback, reducing frustration and confusion.
Postal mail delivery system
Both involve sending messages that can fail or be delayed, requiring checks and retries.
Seeing network calls like mail delivery helps understand why error handling and retries are necessary for reliable communication.
Common Pitfalls
#1Ignoring HTTP status codes and only checking the error parameter.
Wrong approach:URLSession.shared.dataTask(with: url) { data, response, error in if error == nil { // Assume success print("Success") } }.resume()
Correct approach:URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { print("Network error: \(error.localizedDescription)") return } if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) { print("Server error: status code \(httpResponse.statusCode)") return } print("Success with data") }.resume()
Root cause:Misunderstanding that URLSession treats HTTP errors as errors in the error parameter.
#2Showing raw error messages directly to users.
Wrong approach:showAlert(message: error.localizedDescription)
Correct approach:showAlert(message: "Unable to connect. Please check your internet and try again.")
Root cause:Not considering user experience and assuming technical messages are helpful.
#3Retrying network calls without limits or delays.
Wrong approach:func fetchData() { networkCall() { success, error in if error != nil { fetchData() // retry immediately } } }
Correct approach:func fetchData(retryCount: Int = 0) { networkCall() { success, error in if error != nil && retryCount < 3 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(retryCount + 1)) { fetchData(retryCount: retryCount + 1) } } } }
Root cause:Not implementing retry limits or backoff strategies.
Key Takeaways
Network calls can fail for many reasons, so always check for errors and handle them gracefully.
URLSession does not treat HTTP error status codes as errors; you must check the response status yourself.
Use Swift's Result type or async/await with do-catch to write clear and safe error handling code.
Provide users with simple, friendly error messages instead of technical jargon to improve experience.
Implement retry logic with limits and delays to recover from temporary network issues without freezing the app.