- July 30, 2025
- Mins Read
A closure in Swift is a self-contained block of functionality that you can pass around and use in your code. Closures can:
Swift uses closures everywhere:
URLSession.shared.dataTask { … }
)map
, filter
, reduce
)Because they’re so flexible and lightweight, closures let you express complex behavior inline, without the ceremony of defining a named function.
A closure’s full form looks a lot like a function:
{ (parameters) -> ReturnType in
// body
}
{ … }
denote the closure.-> ReturnType
tells what it returns.in
keyword separates the signature from the body.let sayHello = {
print("Hello, world!")
}
sayHello() // prints "Hello, world!"
Unlike function declarations, closures are expressions, so their parameter list and return type must live entirely inside the {}
. There’s no separate signature line:
// Function declaration
func add(a: Int, b: Int) -> Int { return a + b }
// Closure expression
let addClosure = { (a: Int, b: Int) -> Int in
return a + b
}
Putting everything inside {}
keeps closures self-contained and emphasizes that you’re creating a first-class value, not defining a top-level function.
Swift can infer parameter types and return types, and even let you use shorthand argument names. That’s why you often see:
// Full form
let sumFull = { (a: Int, b: Int) -> Int in
return a + b
}
// Inferred form
let sumInferred: (Int, Int) -> Int = { a, b in
a + b // implicit return
}
// Shorthand argument names
let sumShorthand: (Int, Int) -> Int = { $0 + $1 }
If your closure takes no parameters but returns something, you still use the -> Type in
syntax and a return
(or implicit return for single expressions):
let randomBool: () -> Bool = {
return Bool.random()
}
// Or shorthand (single expression):
let randomShorthand: () -> Bool = {
Bool.random()
}
// Call it
let value = randomBool()
Below are small “tests” you can paste into a Swift playground or project to verify your understanding of closures.
// Test 1: No parameters, no return
let greet: () -> Void = {
print("Test 1 Passed: Hello from closure!")
}
greet()
Expected output:
Test 1 Passed: Hello from closure!
// Test 2: Parameters, no return
let repeatPrint: (String, Int) -> Void = { message, count in
for _ in 1...count {
print(message)
}
}
print("Test 2 Output:")
repeatPrint("Swift", 3)
Expected output:
Test 2 Output:
Swift
Swift
Swift
// Test 3a: Return an Int
let multiply: (Int, Int) -> Int = { a, b in
return a * b
}
assert(multiply(4, 5) == 20)
print("Test 3a Passed: 4 * 5 == \(multiply(4, 5))")
// Test 3b: No parameters, return Bool
let isEven: (Int) -> Bool = { $0 % 2 == 0 }
assert(isEven(42) == true)
print("Test 3b Passed: 42 is even? \(isEven(42))")
{ (params) -> ReturnType in … }
syntax entirely inside braces.{ $0 + $1 }
).() -> Type
and use return
(or implicit for single expressions).PermissionsSwiftUI displays and handles permissions in SwiftUI. It is largely inspired by SPPermissions. The UI is highly customizable and resembles an Apple style. ...
Introduction PagerTabStripView is the first pager view built in pure SwiftUI. It provides a component to create interactive pager views ...
1. Taking Action When a Property Changes: Property Observers Swift lets you observe and respond to changes in a property’s ...