Swift Tutorial
Swift Data Types
Swift Control Flow
Swift Functions
Swift Collections
Swift OOPs
Swift Additional Topics
In Swift, closures are self-contained blocks of code that can be passed around and used in your code. They're similar to lambdas in other programming languages. Closures can capture and store references to any constants and variables from the context in which they are defined, which is referred to as closing over those constants and variables.
Swift handles memory management of these references for you, which means you don't have to worry about strong reference cycles when capturing values within your closures.
Here's a breakdown of closures in Swift:
{ (parameters) -> return type in statements }
let add: (Int, Int) -> Int = { (a, b) in return a + b } print(add(5, 3)) // Outputs: 8
Swift can infer parameter types and the return type from the context, allowing you to write shorter syntax:
let subtract: (Int, Int) -> Int = { a, b in return a - b }
Single expression closures can return their result implicitly, without using the return
keyword:
let multiply: (Int, Int) -> Int = { a, b in a * b }
Swift provides shorthand argument names starting with $0
, $1
, etc., allowing you to make your closures even more concise:
let divide: (Int, Int) -> Int = { $0 / $1 }
You can pass closures as parameters to functions:
func performOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int { return operation(a, b) } let result = performOperation(10, 5, operation: { $0 + $1 }) print(result) // Outputs: 15
If the last parameter of a function is a closure, you can use trailing closure syntax:
let result2 = performOperation(10, 5) { $0 - $1 } print(result2) // Outputs: 5
If a closure is passed as an argument to a function and is invoked after the function returns, the closure is said to escape the function. Use the @escaping
attribute before the closure's parameter type:
var completionHandlers: [() -> Void] = [] func functionWithEscapingClosure(completionHandler: @escaping () -> Void) { completionHandlers.append(completionHandler) }
Closures can capture values from the surrounding context:
func makeIncrementer(incrementAmount: Int) -> () -> Int { var total = 0 let incrementer: () -> Int = { total += incrementAmount return total } return incrementer } let incrementByTwo = makeIncrementer(incrementAmount: 2) print(incrementByTwo()) // Outputs: 2 print(incrementByTwo()) // Outputs: 4
In this example, incrementByTwo
captures and stores a reference to total
and incrementAmount
from the surrounding context.
Closures are a powerful feature in Swift that allows for flexibility and expressive code. By understanding and mastering closures, you'll be able to write more concise and functional-style Swift code.
How to use closures in Swift:
let simpleClosure = { print("Hello, world!") } simpleClosure() // Prints "Hello, world!"
Swift trailing closures:
func performOperation(completion: () -> Void) { // Perform some operation completion() } performOperation { print("Operation completed!") }
Capturing values in Swift closures:
func makeIncrementer(incrementAmount: Int) -> () -> Int { var total = 0 let incrementer: () -> Int = { total += incrementAmount return total } return incrementer } let incrementByTwo = makeIncrementer(incrementAmount: 2) print(incrementByTwo()) // Prints 2 print(incrementByTwo()) // Prints 4
Swift escaping closures:
var completionHandlers: [() -> Void] = [] func someFunction(completion: @escaping () -> Void) { completionHandlers.append(completion) } someFunction { print("Closure called later") }
Closures vs. functions in Swift:
let addClosure = { (a: Int, b: Int) -> Int in return a + b } func addFunction(a: Int, b: Int) -> Int { return a + b }
Using closures as parameters in Swift:
func operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int { return operation(a, b) } let result = operateOnNumbers(a: 5, b: 3, operation: { $0 * $1 })
Swift closure examples:
let square = { (number: Int) -> Int in return number * number } let numbers = [1, 2, 3] let squaredNumbers = numbers.map(square)
Autoclosures in Swift:
func printMessage(using closure: @autoclosure () -> String) { print(closure()) } printMessage(using: "Hello, autoclosure!")
Handling memory management in Swift closures:
class MyClass { var closure: (() -> Void)? func setupClosure() { closure = { [weak self] in self?.doSomething() } } func doSomething() { // Implementation } }
Swift closure typealias:
typealias MyClosure = (Int, Int) -> Int let add: MyClosure = { $0 + $1 }
Nested closures in Swift:
func outerFunction() { let outerValue = 10 let innerClosure: () -> Void = { print("Inner closure with outerValue: \(outerValue)") } innerClosure() }
Swift escaping and non-escaping closures:
func performOperation(completion: () -> Void) { completion() } func captureClosure(completion: @escaping () -> Void) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { completion() } }
Async closures in Swift:
func fetchData(completion: @escaping (Result<Data, Error>) -> Void) { // Asynchronous operation to fetch data }