SWIFT

Swift Closures: Syntax, Usage, and Examples

Closures in Swift are self-contained blocks of code that capture and store references to variables and constants from their surrounding context. You can assign them to variables, pass them as function arguments, or return them from functions. They provide flexibility and conciseness when writing Swift code, especially for tasks like sorting, event handling, and asynchronous programming.

How to Use Closures in Swift

A closure has a simple structure:

{ (parameters) -> returnType in
    statements
}

You can store a closure in a variable, call it directly, or use shorthand syntax to make it more concise.

Assigning a Closure to a Variable

You can define a closure and store it in a variable for later use.

let multiply: (Int, Int) -> Int = { (a, b) in
    return a * b
}

let result = multiply(4, 5) // Output: 20

Passing a Closure as a Function Parameter

You can pass a closure to a function to execute custom logic.

func performOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}

let sum = performOperation(10, 5, operation: { (x, y) in x + y }) // Output: 15

Using Trailing Closure Syntax

When a closure is the last parameter of a function, you can use trailing closure syntax for better readability.

let result2 = performOperation(8, 3) { $0 - $1 } // Output: 5

When to Use Closures in Swift

Closures are useful whenever you need to pass around logic as a block of code. They are common in event handling, functional programming, and optimizing repetitive tasks.

Sorting Collections

Closures simplify sorting operations by providing inline comparison logic.

let names = ["Liam", "Emma", "Noah", "Olivia"]
let sortedNames = names.sorted { $0 < $1 }

print(sortedNames) // Output: ["Emma", "Liam", "Noah", "Olivia"]

Handling Asynchronous Operations

Closures are essential for handling network requests, animations, and background tasks.

func fetchData(completion: () -> Void) {
    print("Fetching data...")
    completion()
}

fetchData {
    print("Data loaded successfully!")
}

Transforming Collections

Closures help process data efficiently using methods like map, filter, and reduce.

let numbers = [1, 2, 3, 4, 5]
let squaredNumbers = numbers.map { $0 * $0 }

print(squaredNumbers) // Output: [1, 4, 9, 16, 25]

Examples of Closures in Swift

Using Closures as Variables

Closures allow you to store and reuse functions dynamically.

let greet: (String) -> String = { name in
    return "Hello, \(name)!"
}

print(greet("Sophia")) // Output: Hello, Sophia!

Returning a Closure from a Function

A function can return a closure, making it possible to create reusable logic.

func makeMultiplier(by factor: Int) -> (Int) -> Int {
    return { number in number * factor }
}

let triple = makeMultiplier(by: 3)
print(triple(4)) // Output: 12

Optional Closures

Closures can be optional, allowing you to define them only when needed.

var onCompletion: (() -> Void)?

onCompletion = {
    print("Task completed!")
}

onCompletion?() // Output: Task completed!

Capturing Values in Closures

Closures capture variables from their surrounding context, allowing them to persist between calls.

func makeCounter() -> () -> Int {
    var count = 0
    return {
        count += 1
        return count
    }
}

let counter = makeCounter()
print(counter()) // Output: 1
print(counter()) // Output: 2

Learn More About Closures in Swift

Swift provides additional closure capabilities like escaping closures, autoclosures, and capturing lists.

Escaping Closures

An escaping closure outlives the function it was passed into, making it useful for delayed execution.

var completionHandlers: [() -> Void] = []

func addTask(completion: @escaping () -> Void) {
    completionHandlers.append(completion)
}

addTask {
    print("Deferred task executed!")
}

Autoclosures

An autoclosure delays execution until the closure is called explicitly.

func logMessage(_ message: @autoclosure () -> String) {
    print(message())
}

logMessage("Logging started") // Output: Logging started

Closure vs. Function

Closures work similarly to functions but are more compact and flexible.

func add(a: Int, b: Int) -> Int {
    return a + b
}

let closureAdd: (Int, Int) -> Int = { $0 + $1 }

print(add(a: 5, b: 3))      // Output: 8
print(closureAdd(5, 3))     // Output: 8

Best Practices for Using Closures

  • Use trailing closure syntax when the last parameter is a closure.
  • Capture values carefully to avoid retain cycles, especially when using closures with classes.
  • Keep closures concise by using shorthand syntax ($0, $1) where applicable.
  • Use escaping closures for long-running tasks that execute later.
  • Consider autoclosures for lazy execution when passing expressions instead of function calls.
Learn to Code in Swift for Free
Start learning now
button icon
To advance beyond this tutorial and learn Swift by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH