Rethrowing functions let you pass errors up without handling them immediately. This helps keep your code clean and lets the caller decide how to handle errors.
Rethrowing functions in Swift
func yourFunction(closure: () throws -> Void) rethrows { try closure() }
The rethrows keyword means your function only throws if the passed-in closure throws.
You must use try when calling the closure inside your function.
func perform(action: () throws -> Void) rethrows { try action() }
func runTwice(action: () throws -> Void) rethrows { try action() try action() }
rethrows.func noThrow(action: () -> Void) {
action()
}This program defines a function callTwice that rethrows errors from a closure it calls twice. It shows calling it with a closure that does not throw and one that throws an error. The error is caught outside the rethrowing function.
enum SimpleError: Error { case exampleError } func callTwice(action: () throws -> Void) rethrows { try action() try action() } func mightThrow(shouldThrow: Bool) throws { if shouldThrow { throw SimpleError.exampleError } else { print("No error") } } // Using callTwice with a throwing closure print("Calling with no error:") try? callTwice { try mightThrow(shouldThrow: false) } print("Calling with error:") do { try callTwice { try mightThrow(shouldThrow: true) } } catch { print("Caught an error") }
Use rethrows only when your function calls a throwing closure and you want to pass errors up.
If your function can throw errors on its own, you cannot use rethrows; use throws instead.
Rethrowing helps keep error handling flexible and clear.
Rethrowing functions let you pass errors from closures up to the caller without handling them inside.
Use rethrows when your function only throws if the closure throws.
This keeps your code clean and lets callers decide how to handle errors.
Practice
rethrows keyword indicate in a Swift function?Solution
Step 1: Understand the role of
Therethrowsrethrowskeyword means the function itself does not throw errors unless the closure it accepts throws.Step 2: Compare options with this meaning
The function only throws an error if the closure it receives throws an error. correctly states this behavior. Options B, C, and D misunderstand the conditional throwing nature ofrethrows.Final Answer:
The function only throws an error if the closure it receives throws an error. -> Option CQuick Check:
rethrows means conditional throwing = A [OK]
- Thinking rethrows means always throws
- Confusing rethrows with throws
- Assuming rethrows catches errors
operation?Solution
Step 1: Identify correct placement of
The closure parameter must be declared withthrowsandrethrowsthrowsif it can throw, and the function must be markedrethrowsto propagate errors conditionally.Step 2: Check each option
func perform(operation: () throws -> Void) rethrows {} correctly declares the closure as() throws -> Voidand the function asrethrows. func perform(operation: () rethrows -> Void) throws {} incorrectly usesrethrowson the closure. func perform(operation: () throws -> Void) throws {} marks the function asthrowsinstead ofrethrows. func perform(operation: () -> Void) rethrows {} declares a non-throwing closure but marks the function asrethrows, which is invalid.Final Answer:
func perform(operation: () throws -> Void) rethrows {} -> Option DQuick Check:
Closure throws + function rethrows = A [OK]
- Using rethrows on closure instead of function
- Marking function as throws instead of rethrows
- Marking function rethrows with non-throwing closure
func execute(task: () throws -> String) rethrows -> String {
return try task()
}
func successTask() throws -> String {
return "Success"
}
func failTask() throws -> String {
throw NSError(domain: "Error", code: 1)
}
print(try execute(task: successTask))Solution
Step 1: Understand function behavior with successTask
Theexecutefunction callstask()which issuccessTaskhere. SincesuccessTaskreturns "Success" without throwing,executereturns "Success".Step 2: Analyze output of print statement
The print statement outputs the returned string "Success". No errors are thrown or caught here.Final Answer:
Success -> Option AQuick Check:
Successful closure call prints result = B [OK]
- Assuming error is thrown when closure succeeds
- Confusing rethrows with always throws
- Expecting silent error handling
func run(operation: () throws -> Void) rethrows {
do {
try operation()
} catch {
print("Caught error")
}
}
func risky() throws {
throw NSError(domain: "Fail", code: 0)
}
try run(operation: risky)Solution
Step 1: Understand rethrows and error catching
A function markedrethrowsmust not catch errors from the closure; it only propagates them. Catching errors inside breaks this rule.Step 2: Analyze the code's catch block
Therunfunction catches errors fromoperation()internally, so it cannot be markedrethrows. This causes a compile error.Final Answer:
The function cannot be marked rethrows if it catches errors internally. -> Option AQuick Check:
rethrows disallows internal catch = D [OK]
- Marking function rethrows but catching errors inside
- Confusing rethrows with throws
- Expecting rethrows to handle errors silently
processAll that takes an array of closures, each possibly throwing an error, and calls them all. If any closure throws, processAll should rethrow that error. Which is the best way to declare processAll?Solution
Step 1: Understand rethrows limitation
Therethrowskeyword only works if the function takes exactly one throwing closure parameter. Here,tasksis an array of closures, sorethrowscannot be used.Step 2: Choose correct error propagation
Since multiple closures can throw,processAllmust be markedthrowsto propagate errors. func processAll(tasks: [() throws -> Void]) throws { for task in tasks { try task() } } correctly usesthrows. func processAll(tasks: [() throws -> Void]) rethrows { for task in tasks { try task() } } incorrectly usesrethrows. func processAll(tasks: [() -> Void]) rethrows { for task in tasks { task() } } uses non-throwing closures. func processAll(tasks: [() throws -> Void]) { for task in tasks { try? task() } } ignores errors withtry?.Final Answer:
func processAll(tasks: [() throws -> Void]) throws { for task in tasks { try task() } } -> Option BQuick Check:
Multiple throwing closures require throws, not rethrows = C [OK]
- Using rethrows with multiple throwing closures
- Ignoring errors with try?
- Declaring non-throwing closures when errors can occur
Ready to prove it?
Pass the test and this pattern moves unknown
