SWIFT
Swift Try Catch: Syntax, Usage, and Examples
Swift try catch is part of Swift’s error handling system. It allows you to attempt code that might fail and handle any errors that occur. Instead of crashing, your app can respond to problems gracefully—whether you're reading a file, decoding JSON, or connecting to an API.
How to Use Try Catch in Swift
Swift uses a combination of do
, try
, and catch
to handle errors. You place potentially failing code inside a do
block and handle errors in a catch
block.
Basic Syntax of Try Catch Swift
do {
try someFunctionThatThrows()
} catch {
print("An error occurred: \(error)")
}
The try
keyword marks a function that can throw an error. If it does, the control passes to the catch
block. If not, execution continues normally.
Defining Your Own Throwing Functions
Here’s how to create a function that can throw:
enum FileError: Error {
case fileNotFound
}
func readFile(named name: String) throws -> String {
guard name == "data.txt" else {
throw FileError.fileNotFound
}
return "File contents"
}
Now you can use this with Swift try catch:
do {
let contents = try readFile(named: "wrong.txt")
print(contents)
} catch {
print("Failed to read file.")
}
If readFile
throws fileNotFound
, the catch block handles it.
When to Use Try Catch in Swift
Swift try catch comes in handy any time you call a function that can fail. Use it when:
- Reading or writing files that might be missing or unreadable.
- Decoding JSON that may be incorrectly formatted.
- Performing network calls that can fail due to connection issues or bad responses.
- Using APIs that mark their methods with
throws
. - Validating inputs or processing data that might be invalid.
Try catch Swift gives you control over these failure points so you can inform users or take alternative actions.
Examples of Try Catch Swift in Practice
Reading a File with Error Handling
enum FileError: Error {
case missing
}
func openFile(name: String) throws -> String {
if name != "document.txt" {
throw FileError.missing
}
return "This is the file content."
}
do {
let file = try openFile(name: "notes.txt")
print(file)
} catch {
print("Could not open file.")
}
This example uses do try catch Swift logic to manage file-related issues.
Parsing JSON with Do Try Catch Swift
struct User: Decodable {
let name: String
}
let json = """
{ "name": "Taylor" }
""".data(using: .utf8)!
do {
let user = try JSONDecoder().decode(User.self, from: json)
print("Hello, \(user.name)")
} catch {
print("Failed to decode JSON")
}
JSON decoding is one of the most common reasons to use try catch Swift in modern iOS development.
Using Multiple Catch Blocks
You can write multiple catch
blocks to handle specific error types:
enum NetworkError: Error {
case timeout
case noConnection
}
func fetchData() throws {
throw NetworkError.timeout
}
do {
try fetchData()
} catch NetworkError.timeout {
print("Request timed out.")
} catch NetworkError.noConnection {
print("No internet connection.")
} catch {
print("An unknown error occurred.")
}
This approach lets you respond differently to different failure scenarios.
Learn More About Try Catch in Swift
Optional Try (try?)
Sometimes you want to try something but ignore the error if it fails. That’s where try?
comes in. It returns an optional value: the result if the function succeeds, or nil
if it fails.
func convert(_ input: String) throws -> Int {
guard let number = Int(input) else {
throw NSError(domain: "", code: 0)
}
return number
}
let value = try? convert("42") // value is Optional(42)
let fail = try? convert("abc") // fail is nil
Use try?
when failure isn’t critical and you’re okay with silently failing.
Forced Try (try!)
If you're sure a function won’t throw, or you're okay with crashing if it does, use try!
.
let result = try! convert("123")
Avoid try!
unless you’re absolutely sure—because if an error is thrown, your app crashes.
Re-throwing Functions
You can create functions that accept other throwing functions and re-throw any errors.
func runTask(_ task: () throws -> Void) rethrows {
try task()
}
This helps you write wrapper functions that preserve the ability to throw errors.
Nesting Try Catch Swift Blocks
You can nest do try catch
inside other blocks. For example:
func performTask() {
do {
try fetchData()
} catch {
print("Task failed: \(error)")
}
}
Each block only handles the specific errors thrown inside it.
Custom Error Messages
Inside catch
, you get an error
object. You can inspect or convert it:
catch let err as MyCustomError {
print("Specific error: \(err)")
} catch {
print("General error: \(error.localizedDescription)")
}
This helps with debugging and user feedback.
Throwing Initializers
You can mark initializers with throws
, too:
struct Profile {
let age: Int
init(age: Int) throws {
guard age > 0 else { throw NSError(domain: "", code: 0) }
self.age = age
}
}
do {
let profile = try Profile(age: 25)
print("Age: \(profile.age)")
} catch {
print("Invalid age")
}
This approach helps with model validation and setup.
Swift Error Handling vs Objective-C
In Objective-C, you check NSError
pointers. Swift try catch replaces that with a modern, cleaner syntax. Errors become typed values, not just return codes.
Best Practices for Try Catch Swift
- Always handle errors where they occur or bubble them up responsibly.
- Use specific catch blocks when you can for clearer logic.
- Don’t overuse
try!
—crashes hurt user experience. - Use
try?
only when silent failure is acceptable. - Prefer custom error types with meaningful names and cases.
- Add context when printing or logging errors—raw
error
isn’t always helpful. - Keep throwing functions small and focused.
Swift try catch gives you a safe, expressive way to deal with failures without cluttering your code with error codes or flags. From decoding a response to validating a file, handling errors the Swift way makes your app more stable and easier to debug.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.