Closures in Depth
Closures are blocks of code you can pass around like values. This lesson covers full and shorthand syntax, trailing closures , capturing values, and the difference between escaping and non-escaping closures — the foundation of callbacks and functional Swift.
Learn Closures in Depth in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Closure Syntax
The full closure form is {' (params) -> ReturnType in body '} . The in keyword separates the signature from the body. A closure can take no parameters and return nothing — its type is then () -> Void .
2️⃣ Trailing Closures
When a closure is the last argument to a function, you can write it after the parentheses. This trailing-closure style is everywhere in Swift and SwiftUI because it reads so cleanly.
3️⃣ Shorthand: $0, Inferred Types & Returns
Swift lets you drop a lot of ceremony. Parameter types can be inferred, a single-expression body needs no return , and $0 / $1 name the arguments positionally.
4️⃣ Capturing Values (and Escaping)
A closure captures variables from the scope where it's defined and keeps them alive. A closure that's stored and called after the function returns is escaping — you mark its parameter @escaping , and using self inside it must be explicit.
Your turn. Fill in the blanks to use shorthand arguments and the in keyword.
📋 Quick Reference
No blanks this time — just a brief and an outline. Build it, run it, and check your output against the example in the comments.
Practice quiz
What is a closure in Swift?
- A class that can't be subclassed
- A type of optional
- A self-contained block of code that can be passed around
- A protocol requirement
Answer: A self-contained block of code that can be passed around. A closure is a self-contained block of functionality that can be stored, passed, and called later.
What keyword separates a closure's parameters from its body?
- in
- return
- do
- then
Answer: in. The 'in' keyword separates the parameter/return list from the closure body.
What is a trailing closure?
- A closure stored in a variable
- A closure that returns nothing
- A closure with no parameters
- A closure written after the call's parentheses when it's the last argument
Answer: A closure written after the call's parentheses when it's the last argument. When a closure is the final argument, you can move it outside the parentheses as a trailing closure.
What does the shorthand argument $0 refer to?
- The return value
- The first parameter of the closure
- The closure itself
- An optional binding
Answer: The first parameter of the closure. $0 is shorthand for the first parameter, $1 the second, and so on.
What does it mean to 'capture' a value in a closure?
- To keep a reference to a variable from the surrounding scope
- To copy it into a struct
- To make it constant
- To delete it after use
Answer: To keep a reference to a variable from the surrounding scope. A closure captures variables/constants from its surrounding context and can keep using them.
What is an escaping closure?
- A closure that throws errors
- A closure that can't capture values
- A closure stored and called AFTER the function returns
- A closure with no body
Answer: A closure stored and called AFTER the function returns. An @escaping closure outlives the function call — it's stored and invoked later, e.g. in a completion handler.
By default, are closure parameters to a function escaping or non-escaping?
- Escaping
- Non-escaping
- Always escaping for async
- Neither — it must be specified
Answer: Non-escaping. Closure parameters are non-escaping by default; you opt in to escaping with @escaping.
When can you omit a closure's 'return' keyword?
- Never
- Only for trailing closures
- Only when it returns Void
- When the closure body is a single expression
Answer: When the closure body is a single expression. For a single-expression closure, Swift infers the return, so you can omit 'return'.
Which is a valid empty closure type that takes no parameters and returns nothing?
- Void -> Int
- () -> ()
- (Int)
- { }
Answer: () -> (). () -> () (or () -> Void) is a closure taking no arguments and returning nothing.
Why might @escaping closures require you to write self explicitly?
- For performance
- Because self is optional
- To make capturing of self visible and avoid accidental retain cycles
- It is never required
Answer: To make capturing of self visible and avoid accidental retain cycles. Escaping closures that use self require explicit self, making the strong capture (and possible retain cycle) obvious.