Escaping closures let you use a piece of code later, even after the function that got it finishes. This helps when you want to do something after waiting or in the background.
Escaping closures (@escaping) in Swift
func someFunction(completion: @escaping () -> Void) { // function body }
The @escaping keyword tells Swift the closure might be called later, not immediately.
Without @escaping, the closure must be used before the function ends.
@escaping.func performTask(completion: @escaping () -> Void) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { completion() } }
@escaping is not needed.func saveData(completion: () -> Void) {
completion()
}This program simulates fetching data asynchronously. The closure is marked @escaping because it runs after the function returns. The program waits 3 seconds to show the result.
import Foundation func fetchData(completion: @escaping (String) -> Void) { DispatchQueue.global().async { // Simulate network delay sleep(2) let data = "Hello from network" DispatchQueue.main.async { completion(data) } } } print("Start fetching...") fetchData { result in print("Received: \(result)") } // Keep the program running to see async result RunLoop.main.run(until: Date(timeIntervalSinceNow: 3))
Use @escaping only when the closure is called after the function returns.
Escaping closures can capture variables and keep them alive longer.
Be careful with retain cycles when using escaping closures inside classes.
Escaping closures run after the function ends.
Mark closures with @escaping if they run later or asynchronously.
They help with callbacks, delays, and asynchronous tasks.
Practice
@escaping keyword indicate in Swift closures?Solution
Step 1: Understand closure execution timing
Closures without@escapingrun inside the function before it returns.Step 2: Role of
Marking a closure@escaping@escapingmeans it can be stored and called later, after the function ends.Final Answer:
The closure can be called after the function returns -> Option AQuick Check:
@escapingmeans delayed closure call [OK]
- Thinking @escaping closures run immediately
- Confusing @escaping with synchronous execution
- Believing @escaping closures cannot capture variables
Solution
Step 1: Identify correct placement of @escaping
The@escapingkeyword must appear before the closure type in the parameter list.Step 2: Check each option's syntax
func fetchData(completion: @escaping () -> Void) {} correctly places@escapingbefore the closure type. Options A, C, and D have incorrect syntax.Final Answer:
func fetchData(completion: @escaping () -> Void) {} -> Option DQuick Check:
Correct syntax = func fetchData(completion: @escaping () -> Void) {} [OK]
- Placing @escaping before parameter name
- Omitting @escaping for delayed closures
- Writing 'escaping' without @ symbol
func performTask(completion: @escaping () -> Void) {
DispatchQueue.main.async {
completion()
}
print("Task started")
}
performTask {
print("Task completed")
}Solution
Step 1: Understand async dispatch behavior
The closure passed toDispatchQueue.main.asyncruns later, after the current function finishes.Step 2: Trace print statements order
"Task started" prints immediately. Then the closure runs and prints "Task completed".Final Answer:
Task started\nTask completed -> Option CQuick Check:
Async closure runs after print [OK]
- Assuming closure runs before print
- Ignoring async dispatch delay
- Confusing order of print statements
func saveData(completion: () -> Void) {
DispatchQueue.global().async {
// Save operation
completion()
}
}Solution
Step 1: Analyze closure usage inside async block
The closure is called asynchronously after the function returns, so it must be marked@escaping.Step 2: Check function parameter declaration
The parameter lacks@escaping, causing a compile error.Final Answer:
Missing @escaping before closure parameter -> Option AQuick Check:
Async closure needs @escaping [OK]
- Forgetting @escaping for async closures
- Assuming closure is synchronous by default
- Adding unnecessary optional to closure
class NetworkManager {
var completionHandler: (() -> Void)?
func requestData(completion: ???) {
self.completionHandler = completion
// Simulate network delay
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
self.completionHandler?()
}
}
}Solution
Step 1: Understand closure storage and delayed call
The closure is saved in a property and called later asynchronously, so it must be@escaping.Step 2: Evaluate options for closure parameter
Only completion: @escaping () -> Void correctly marks the closure as@escaping. Options A, B, and D are incorrect or unnecessary here.Final Answer:
completion: @escaping () -> Void -> Option BQuick Check:
Stored closures must be @escaping [OK]
- Omitting @escaping when storing closures
- Using @autoclosure unnecessarily
- Marking closure without @escaping for delayed call
Ready to prove it?
Pass the test and this pattern moves unknown
