Closures In Swift And It’s Related Importance

tudip-logo

Tudip

09 September 2019

Closures in Swift

Closure is everywhere in Swift. If you are working with Swift you must be using closure.

What is closure?

Closures are self-contained blocks of functionality that can be passed around and used in your code

  • Swift Documentation.
Let’s see an example of closure:

{Code}

let isEven = { (value: Int) -> Bool in

return (value % 2 == 0) ? true : false

}

print("5 is \(isEven(5))")

{Code}

 

Code Snippet – 1

Everything within the brackets { } is called as the Closure expression.

Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context

  • Swift documentation
Closure expression syntax:

{ (parameters) -> return type in

statement

}

In code snippet – 1

  • The parameter name is “value” which is of type “Int”.
  • The return type is “bool”.
  • Statement and parameters are separated by “in” keyword.

 

There are various optimizations provided to the closure expression.

  1. Closure expression can Infer types from it context.

Swift infers the type of the parameter and type of the value it returns from the context.

We will modify the closure expression in Code Snippet – 1.

let isEven = { value in

return (value % 2 == 0) ? true : false

}

print("5 is \(isEven(5))")

 

Code Snippet – 2 

In the above code snippet swift automatically infers the type of value and its return type. We don’t need to explicitly define the parameter type as an Int and return type as a bool.

  1. Single expression closure can implicitly return.

Single expression closure can implicitly return the result without using return keyword.

So, we can skip the return keyword for the closure containing the single expression.

We will modify the closure expression in Code Snippet – 1

let isEven = { value in (value % 2 == 0) ? true : false }

print("5 is \(isEven(5))")

 

Code Snippet – 3

Note: For Closure with multiple expressions we should use return statement explicitly.

  1. Shorthand Argument names

Swift provides shorthand argument like $0, $1 and so on to refer to the parameters of the closure expression

We will again modify the closure expression in Code Snippet – 1

let isEven = { ($0 % 2 == 0) ? true : false }

print("5 is \(isEven(5))")

Code Snippet – 4

In the above code snippet we have replaced the parameter value with $0.

  1. Trailing Closure

Whenever we are passing closure in the function call and closure expression is long, we can write the closure expression as trailing closure.

Even if the trailing closure is an argument of the function call it is written after the parentheses of the function.

Note: As the name suggests, Trailing closure should be the last parameter of the function call.

func validateName(name: String, printName: (String) -> ()) {

// print name if it contains more than 5 characters

if name.count > 5 {

printName(name)

}

}

validateName(name: "Peter Parker") { (name) in

print("Name with more than 5 characters \(name)")

}

Code Snippet – 5

In the above code snippet we pass a closure as the final argument to the validateName function.

Trailing closure adds syntactic sugar and increases the code readability.

Closure can capture values.

Closure can capture and modify the variables and constants from the context in which they are defined.

The value of the captured variable and constants can be modified within the closure even if the original scope that defined the constant and variable no longer exists.

func outerFunc() -> (Int) -> ()

{

var count = 0

func innerFunc(i: Int) {

count += i    // value of count variable is captured

print(count)

}

return innerFunc

// Counter variable should be destroyed here.

// But it is kept alive to used by outerFunc.

}


let storeFunc = outerFunc()

storeFunc(7) // prints 7

storeFunc(8) // prints 15

// The count variable is created once and is captured by innerFunc

// Everytime innerFunc gets called counter is updated.

Code Snippet – 6

In the above code snippet outerFunc returns a function which takes an Int as a parameter.

innerFunc captures the variable count which is defined within outerFunc and it is not destroyed when the scope of the outerFunc ends.

Escaping Closures

When the closure is passed to a function which gets executed after the function returns then it is known as an escaping Closures.

In order to make a closure escaping, we add @escaping before the closure type in the function argument

func performTask(completion: @escaping () -> ()) {

print("Performing task")

// Delay the execution of the closure by 0.5 sec

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {

completion()

}

return

}

performTask() {

print("Completed all task")

}

 

Code Snippet – 7

In the above example, the function “performTask” returns by executing the print statement. While the execution of the closure is delayed by 0.5 secs.

Escaping closure are very useful to mark the completion of an API call or completion of an animation.

Note: By default closure in swift are non-escaping in nature i.e the closure gets executed before the function returns.

Request a quote