Functional swift: All about Closures

According to apple docs: Closures are self-contained blocks of functionality that can be passed around and used in your code. I tried to include all about closures here in this article. It’s a bit lengthy one. But worth reading it. I guarantee !!!

I don’t know who that is, But the photo looks refreshing. isn’t??
Some people say that Functions and closures are the same thing with different syntax. Others say that functions are special kind of closure.
Closures are first-class objects, so that they can be nested and passed around

First, let us know what a function is:

Function:

You define a function with the func keyword. Functions can take many parameters and return none, one or multiple parameters (using tuples, we can return multiple values at a time).

function that takes two parameters and returns two parameters using tuples

The above function will take two integers as input and returns a tuple with two integer values. If you have no experience with a tuple, please check my other article here.

Function types

Let’s consider a simple function which takes an int and returns an int .

func doSometingWithInt(someInt:Int) -> Int {
return someInt * 2
}

Every function has its own function type, made up of the parameter types and the return type of the function itself. The function type of the above function will be :

(int) -> (int)

If the function takes two parameters, and return one parameter, the type will be:

(int, int) -> (int)

This function type can be used as return type from nested functions or as parameters.

func personInTheHouse() -> ((String) -> String) {
func doProcess(process: String) -> (String) { // nested function
return “The person is \(process).”
}
return doProcess // or return doProcess(process:)
}
let person = personInTheHouse()
print(person(“playing cricket”)) // prints “The person is playing cricket.

Defining a closure :

Understanding a closure syntax is pretty easy. You now knows what a function type is. Just put the function type within a pair of curly braces and add a in keyword after the return type. The in keyword is followed by the statements. It became a closure expression.

{ (params) -> returnType in
statements
}
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context. Closure expression syntax is given in the code block above.
  • Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent.
  • The parameters in closure expression syntax can be in-out parameters, but they can’t have a default value. Variadic parameters can be used if you name the variadic parameter. Tuples can also be used as parameter types and return types.

Let’s create a function which accepts two int values and return the sum as int.

func addTwoNumbers(number1:Int, number2:Int) -> Int {
return number1 + number2
}
addTwoNumbers(number1: 8, number2: 2) // result is 10

Now let’s create a closure for the same operation:

let closure: (Int, Int) -> Int = { (number1, number2) in
return number1 + number2
}
closure(8,2) // the result is 10

The function and closure looks more or like similar in the number of lines of code, readability etc.. Lets try to simplify the closure even simpler.

Shorthand Argument Names

Closure arguments can be references by position ($0, $1, …) rather than by name.

var shortHandClosure:(Int,Int)->Int = {
return $0 + $1
}
shortHandClosure(8,2) // result is 10

Since , the closure’s body contains a single expression which returns an Int value, we can omit the return statement. If there are multiple lines of code inside the closure body, then we cannot omit the return statement.

var superShortClosure:(Int,Int)->Int = {$0 + $1}

Now, this looks very much different from the function that we defined in the beginning . This is much simpler and more meaningful as well.

Note: If we had to write an additional print statement along with the return expression, we cannot omit the return statement.
Our objective is to write less code.

Inferred type closure

A closure of type (Int,Int)->Int is inferred in the following code:

let inferredClosure = {(x:Int,y:Int)->Int in x + y }
inferredClosure(1,99) // result is 100

Return types can also be inferred:

let inferredReturnTypeClosure = {(number:Int) in number*number }

What do you expect the type of the above closure to be?, It returns an int .

It is (Int) -> Int

Closure that takes nothing and returns a string:

A closure can be of type () -> (SomeType) .

The following is a closure that takes no parameters and returns a string.

let callStringWtihClosure: () -> String = { () in 
return “hello”
}
//____________
print(callStringWtihClosure()) // prints “hello”

Since, we don’t care about the input parameters here, we can omit the () in inside the closure body.

The closure type for the one below will be () -> String

let callStringWtihClosure: () -> String = {return “hello”}

Also, since it returns a String and it doesn’t take any parameters, we can omit the type as well.

The closure type for the one below will be () -> String

let callStringWithClosureWithoutType = { “hi, I’m a closure too” }

Closures and functions are first class types in swift:

Functions and closures are first-class citizens in Swift because you can treat then like a normal value. For example, you can …

  • assign a function/closure to a local variable .
  • pass a function/closure as an argument .
  • return a function/closure .

Methods with completion callback using closures:

Here is my Article on Methods with completion callback using closures. Do read this.

The following code has a function which has three parameters. One is a dictionary , other two are closures which will act as callback functions after when the process is done.

the @escaping keyword before the closure in the function definition will be explained in the following sections.

Returning a closure from a function

We can return a closure from a function. Check the code below.

// return a closure from a function
var addClosure:(Int,Int)->Int = { $0 + $1 }
func returnClosure() -> (Int,Int)->Int {
return addClosure
}
//____________________________________
returnClosure()(10,20) // returns 30
var returnedClosure = returnClosure() // returns a closure of type (Int,Int)->Int
returnedClosure(20,10) // returns 30

Initialize or customize objects using closures

I normally use functions to setup or customize an object. But closure code looks simple and understanding.

Create a UIView ,customize it using a function and return it. Create a function of type () -> UIView .

func setupView() -> UIView {
let view = UIView()
view.backgroundColor = .red
return view
}
let someView = setupView() // returns a red view

Now, do the same with a closure of type () -> UIView . In the below code setupViewUsingClosure is a closure of type () -> UIView .

let setupViewUsingClosure = { () -> UIView in
let view = UIView()
view.backgroundColor = .green
return view
}
let someOtherView = setupViewUsingClosure() // returns a green view

The above method can further be simplified into the following syntax where we can directly initialize an object using a closure.

let setupViewUsingClosure: UIView = {
let view = UIView()
view.backgroundColor = .green
return view
}() //IMPORTANT!!! I have added () at the end.

In the above code setupViewUsingClosure is a UIView object . The code towards the RHS of the expression is actually a closure of type () -> UIView . Let’s make it more clear.

let aClosure= { “hello, I’m a closure too.” }
let aString= { “hello, I’m a closure too.” }() // added () at the end.

In the first statement, aClosure is actually a closure of type ()->String .

IN the second statement, we added () at the end .So it became a closure call. So, it executes the closure and returns a String . If it is not clear, refer the Inferred type closure section above.

lazy init:

Please do read the following article to know more about lazy var in swift. It explains how a lazy var works. : lazy var in ios swift. This is important and a must read.

Trailing Closures

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. A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.

func doSomething(number:Int,onSuccess closure:(Int)->Void) {
closure(number * number * number)
}
doSomething(number: 100) { (numberCube) in
print(numberCube) // prints  1000000
}

The argument label onSuccess is not there in the function call. Even though the closure is included in the function parameters list, swift will take it out of the parameter block to make the code more readable.

Capturing values

Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables (This is explained in the later part of this article.). Swift handles all of the memory management of capturing for you.

Consider the following code:

// capturing values
var i = 0
var closureArray = [()->()]()
for _ in 1…5 {
closureArray.append {
print(i)
}
i += 1
}
// here i will be 5
closureArray[0]() // prints 5
closureArray[1]() // prints 5
closureArray[2]() // prints 5
closureArray[3]() // prints 5
closureArray[4]() // prints 5

For every iteration of the for loop, we created an empty closure ()->() and added it to an array called closureArray . Closure body contains only a single statement which prints i . The closure captures the current address of i and every time we access i , it . returns the current value.

As mentioned above, the memory issues related to this capturing is handled by swift. We don’t have to worry about it.

Important points are:

  • A closure can capture constants and variables from the surrounding context in which it is defined.
  • The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
  • Swift also handles all memory management involved in disposing of variables when they are no longer needed.
  • If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles.

Creating a capture list:

If we want to prevent this behavior (capturing values) and print the value of i even if the properties change after their capturing inside the closure, we can explicitly capture the variable with a capture list like this:

var closureArray2 = [()->()]()
var j = 0
for _ in 1…5 {
closureArray2.append { [j] in
print(j)
}
j += 1
}
// here i will be 5
closureArray2[0]() // prints 0
closureArray2[1]() // prints 1
closureArray2[2]() // prints 2
closureArray2[3]() // prints 3
closureArray2[4]() // prints 4

In this way, we keep an immutable copy of the variable j. Thanks to this copy, further changes to j, outside the closure, will not affect the closure. J is a let constant here. It is not mutable.

We can add multiple values to the capture list :

closure.append { [j,k,l] in
print("\(j) \(k) \(l)")
}

also, you can have alias names for the values captured.

closure.append { [a = j, b = k, c = l] in
print("\(j) \(k) \(l)")
}

Escaping closure vs non-escaping closure

There are two kinds of closures:

  • An escaping closure is a closure that’s called after the function it was passed to returns. In other words, it outlives the function it was passed to.
  • A non-escaping closure is a closure that’s called within the function it was passed into, i.e. before it returns.

@noescape was an attribute in swift 2. This is deprecated from swift 3. The @noescape attribute is applied by default in Swift 3. Because closures are by default non-escaping in Swift 3, escaping closures need to be marked as such. And the @escaping attribute lets us do that.

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

A good example of an escaping closure is a completion handler. It’s executed in the future, when a lengthy task completes, so it outlives the function it was created in. Another example is asynchronous programming: a closure that’s executed asynchronously always escapes its original context.

func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandler()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}

You may have noticed that the @escaping attribute precedes the type of the parameter, not the name. This too is new in Swift 3.

Marking a closure with @escaping means you have to refer to self explicitly within the closure. For example, in the code below, the closure passed to someFunctionWithEscapingClosure(_:) is an escaping closure, which means it needs to refer to self explicitly. In contrast, the closure passed to someFunctionWithNonescapingClosure(_:) is a nonescaping closure, which means it can refer to selfimplicitly.

You can use the self keyword without issues in non-escaping closures because the closure is invoked before the function returns. There is no need to use a weak reference to self in the closure. This is a nice benefit you get for free.

Memory management

Do read “Creating a capture list:” part above and understand what capturing and capturing list is.

A strong reference cycle occurs when two objects keep a strong reference of each other. Because of this cycle, the two objects won’t be deallocated, since their reference count doesn’t drop to zero. By default, a closure keeps a strong reference of the variable captured.

Consider the following example.

class InterviewTest {
var name: String = “Abhilash”
lazy var greeting : String = {
return “Hello \(self.name)”
}()
}
//-------------------------
let testObj = InterviewTest()
testObj.greeting // result is Hello Abhilash

The lazy var greeting is returning a string by accessing the local variable name from the class InterviewTest . We cannot directly access the variable. We have to use self keyword to do that. But as explained, by default, a closure keeps a strong reference of the variable captured. It may cause reference cycles.

We can break this strong reference cycle using self in the capture list with either a weak or an unowned reference.

weak

A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle.

Since a weak reference may be nil, the variable captured becomes optional. Therefore, we should use a guard to safely unwrap it:

lazy var greeting : String = { [weak self] in
guard let strongSelf = self else { return “” }
return “Hello \(strongSelf.name)”
}()

Unowned

Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime

lazy var greeting : String = { [unowned self] in
return “Hello \(self.name)”
}()

This means that we should use unowned just when we are sure that the reference will never be nilinside the closure, otherwise the app would crash. So, guard check is not required here.

We can use weak and unowned with any variable in the capture list and we can also combine with the aliases:

lazy var greeting : String = { [unowned unownedSelf = self] in
return “Hello \(unownedSelf.name)”
}()

How to capture self with closures with arguments?

Well, you should capture the self before the internal closure parameter or before the parenthesis of internal parameters. Check the code below. It explains how to capture self in a single parameter case. If you have multiple parameters, you may also use parenthesis.

capturing self along with closure parameters

READ MORE ABOUT CLOSURES HERE.

Autoclosures

An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets you omit braces around a function’s parameter by writing a normal expression instead of an explicit closure.

Overusing autoclosures can make your code hard to understand.
var customersInLine = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”]
print(customersInLine.count)
// Prints “5”
let customerProvider = { customersInLine.remove(at: 0) } // this is of type ()->String
print(customerProvider()) // prints Chris.. the remove(at:) returns a String.

Consider the above function passed on to a function as argument.

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } ) // we cannot omit {}
// Prints "Now serving Alex!"

The serve(customer:) function in the listing above takes an explicit closure that returns a customer’s name. The version of serve(customer:) below performs the same operation but, instead of taking an explicit closure, it takes an autoclosure by marking its parameter’s type with the @autoclosure attribute. Now you can call the function as if it took a String argument instead of a closure. The argument is automatically converted to a closure, because the customerProvider parameter’s type is marked with the @autoclosure attribute.

// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"
If you want an autoclosure that is allowed to escape, use both the @autoclosure and @escaping attributes.

So, in short,

serve(customer: { customersInLine.remove(at: 0) }) // need {}

becomes…..

serve(customer: customersInLine.remove(at: 0)) // omit {}

One more example for explaining autoclosure:

We can create extension on UIView and add something like:

extension UIView {

class func animate(withDuration duration: TimeInterval, _ animations: @escaping @autoclosure () -> Void) {
UIView.animate(withDuration: duration, animations: animations)
}

}

So that,

UIView.animate(withDuration: 2.5) { 
self.view.backgroundColor = .orange
}

becomes….

UIView.animate(withDuration: 2.5, self.view.backgroundColor = .orange)

Last , but not the least!!!

Functions and closures are reference types. Here , in the following code, both addClosure2 and addClosure refers to the same closure in memory.
var addClosure:(Int,Int)->Int = { $0 + $1 }
let addClosure2 = addClosure

Enjoy!!

If you enjoyed reading this post, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

You can follow me on Medium for fresh articles. Connect with me on LinkedIn.

If you have any comment, question, or recommendation, feel free to post them in the comment section below!