What is closure in Swift with example?

In this article, I’ll go over all there is to know about closure. It will teach you all you need to know about closure. I utilized examples rather than words

What is closures in swift-

Closures are self-contained blocks of code that performed a specific task. It is same as function but closures in swift have some properties that make it more powerful than function.

Closure expression syntax –

{ (parameters) −> (return type) in
    statements
}

There are some closure expression in other programming languages.

Closure is same as lambda in C#:
() => { Console.WriteLine($"Outer variable: {outerVariable}"); }

Closure is same as block in Objective C:
^(int a, int b) {
    return a * b;
};

Closure is same as lambda in Java:
Operation add = (a, b) -> a + b;

Examples, How we use Closure in swift programming-

1. Closure as Variable –

Simple closure –

let closure = {
     print("Closure Tutorial”)
}

override func viewDidLoad() {
       super.viewDidLoad()
       closure() 
}
// Output - ‘Closure Tutorial’

Closure with parameter –

let closureWithParameter:(String) -> () = { param  in
      print(param)
}

override func viewDidLoad() {
      super.viewDidLoad()
      closureWithParameter("Closure With Parameter")
}
// Output - ‘Closure With Parameter’


Closure with return value –

let closureWithReturnValue:(String) -> (String) = { param  in
       return "The value: \(param)"
}

Or we can define it as below -

let closureWithReturnValue = { (param: String) -> (String) in
       return "The value: \(param)"
}

override func viewDidLoad() {
       super.viewDidLoad()
       let result = closureWithReturnValue("Closure With Parameter")
       print(result)
}
// Output - The value: Closure With Parameter

2. Closures as Function Parameter

   func getBreakFast(search: () -> ()) {
        // closure call
        search()
   }

  Here you can call this function without using a trailing closure:

   getBreakFast(search: {
        print("Easy grilled & toasted delicious sandwiches")
   })

  you can call this function with a trailing closure instead:

   getBreakFast {
        print("Easy grilled & toasted delicious sandwiches")
   }

Note: We shall talk about trailing closure next.

Categorisation of Closure
-

Trailing closure

If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. Below is trailing closure example

  func getBreakFast(restaurant: String, search: () -> ()) {
        // closure call
        print(restaurant)
        search()
    }

Here, how you call this function without using a trailing closure: We are usoing parameter name and send closure in swift as simple in paramter.

  getBreakFast(restaurant: "Take It Cheesy", search: {
            print("Pizza")
        })

Here, how you call this function with a trailing closure instead: We are not using parameter name, just append closure definition in tail of fincation call.

   getBreakFast(restaurant: "Take It Cheesy") {
            print("Pizza")
        }

Another example trailing closure in swift with parameter

    func getBreakFast(search: (_ dish: String) -> ()) {
        // closure call
        search("Take It Cheesy is 2 miles away")
    }

Calling this function with a trailing closure:

   getBreakFast() { dish in
            print(dish)
        }

Autoclosure

The @autoclosure attribute, when applied to a function’s closure parameter, creates a closure from an expression you pass in. When you call a function with this attribute, the code you write isn’t a closure, but it becomes one, which can be confusing – even the official Swift reference guide warns that using autoclosures excessively makes your code harder to understand.

First we take simple closure example.

 func getBreakFast(search: () -> ()) {
        // closure call
        search()
    }

Here we pass closure with print statement. You can see ‘getBreakFast’ function in his body, call function which pass as closure – search()

 getBreakFast(search: {
            print("Easy grilled & toasted delicious sandwiches")
   })

But with help of @autoclosure, we don’t need to pass the closure as parameter to function. –

    func getBreakFast(search: @autoclosure () -> String) {
        // closure call
        print(search())
    }

Here, we are passing only string what we need to print, and ‘getBreakFast’ function take it as parameter is closure.

    getBreakFast(search: "Autoclosure")

Note: We cannot pass arguments to an autoclosure. If we try to do so we’ll get the error message as:

argument type of @autoclosure parameter must be '()'

Nonescaping Closure

When a closure is passed as a function argument, it is executed along with the function’s body and returns the compiler. When the execution finishes, the passed closure exits scope and no longer exists in memory.

The @nonescaping closure’s lifecycle is as follows:

  1. During the function call, pass the closure as a function argument.
  2. Perform some additional function work.
  3. The closure is executed by function.
  4. The function returns the compiler.

Example:

func nonEscapingClosure(closure: () -> Void) {
    print("Start processing")
    closure()
    print("End processing")
}

nonEscapingClosure {
    print("Executing non-escaping closure")
}
// Output:
// Start processing
// Executing non-escaping closure
// End processing

Escaping closures

When a closure is passed as a function parameter, it is saved to be performed later, and the function’s body is executed, returning the compiler. The scope of the passed closure exists and has existence in memory when the execution finishes, until the closure is performed.

Lifecycle of the @escaping closure:

  1. Pass the closure as function argument, during the function call.
  2. Do some additional work in function.
  3. Function execute the closure asynchronously or stored.
  4. Function returns the compiler back.

Example:

   func escapingClosure(closure: @escaping  () -> Void) {
        print("Start processing")
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            closure() 
        }
        print("End processing") 
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        escapingClosure {
            print("Executing escaping closure")
        }
        
    }

Output - 
Start processing
End processing
Executing escaping closure.   //It will print after 2 second.

‘Closure()’ in ‘escapingClosure’ func will be called with 2 second delay after function completion. Here @escaping define that closure might outlive the function where it is defined.

The @escaping annotation informs the compiler that the closure might be stored or used beyond the duration of the function.

Note: By default, closures are assumed to be non-escaping, meaning they are expected to be executed within the scope of the function they are passed to. If you remove @escaping from parameter of ‘escapingClosure’ function. Compiler will throw below error.

Closure in Swift - All about closure with examples

Here are some reasons why you may use @escaping closures in Swift:

  1. Asynchronous Operations: When you pass a closure to a function that performs an asynchronous operation (e.g., network request, animation), and the closure is executed after the function has returned, the closure needs to escape the scope of that function.
  2. Closures Stored as Properties: If a closure is stored as a property in a class or structure and can be called later, it is considered escaping.
    class Example {
        var completionClosure: (() -> Void)?
        
        func doSomething(completion: @escaping () -> Void) {
            // Store the closure for later use
            completionClosure = completion
        }
    }

The @escaping keyword is necessary here because the closure is stored in the property completionClosure and can be called outside the scope of doSomething().

Capturing Value

Closures are also capable of capturing and storing references to variables and constants from the surrounding context in which they are defined. This process is known as capturing values in a closure. Here’s an example in Swift:

Example:

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0
    
    let incrementer: () -> Int = {
        total += incrementAmount // Here it captures the value of surrounding variable (total) and parameter (incrementAmount)
        return total
    }
    
    return incrementer
}

let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo())  // Prints 2
print(incrementByTwo())  // Prints  4

Closures are reference type

Whenever you assign a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the f closure. This also means that if you assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.

    let alsoIncrementByTwo = incrementByTwo
    print(alsoIncrementByTwo())  // Prints 6
    print(alsoIncrementByTwo())  // Prints 8

The example above shows that calling alsoIncrementByTwo is the same as calling alsoIncrementByTwo. Because both of them refer to the same closure, they both increment and return the same running total.

Note-

  • Global functions are closures that have a name and don’t capture any values.
  • Nested functions are closures that have a name and can capture values from their enclosing function.
  • Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

Conclusion-

We looked at the powerful idea of closures in the Swift programming language in this blog article. Closures are functional units that may be assigned to variables, supplied as arguments, and returned from functions. We discovered that closures provide a succinct and flexible approach to construct code as we investigated its syntax and features.

Furthermore, closures in Swift are classified into three types: global functions, nested functions, and closure expressions. Each kind serves a distinct purpose, offering developers with a range of options.

If you have any query you comment below and reach me out of linked in –
www.linkedin.com/in/chamansharma

One thought on “What is closure in Swift with example?

Leave a Reply

Your email address will not be published. Required fields are marked *