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 !!!

Image for post
Image for post
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 keyword. Functions can take many parameters and return none, one or multiple parameters (using tuples, we can return multiple values at a time).

Image for post
Image for post
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 and returns an .

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 :

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

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

Defining a closure :

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

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 values and return the sum as .

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

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.

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

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 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 is inferred in the following code:

Return types can also be inferred:

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

It is

Closure that takes nothing and returns a string:

A closure can be of type .

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

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

The closure type for the one below will be

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

The closure type for the one below will be

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 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.

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 ,customize it using a function and return it. Create a function of type .

Now, do the same with a closure of type . In the below code is a closure of type .

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

In the above code is a object . The code towards the RHS of the expression is actually a closure of type . Let’s make it more clear.

In the first statement, is actually a closure of type .

IN the second statement, we added at the end .So it became a closure call. So, it executes the closure and returns a . 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.

The argument label 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:

For every iteration of the for loop, we created an empty closure and added it to an array called . Closure body contains only a single statement which prints . The closure captures the current address of and every time we access , 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 even if the properties change after their capturing inside the closure, we can explicitly capture the variable with a capture list like this:

In this way, we keep an immutable copy of the variable . Thanks to this copy, further changes to , 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 :

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

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.

was an attribute in swift 2. This is deprecated from swift 3. The 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 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 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.

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

Marking a closure with means you have to refer to explicitly within the closure. For example, in the code below, the closure passed to is an escaping closure, which means it needs to refer to explicitly. In contrast, the closure passed to is a nonescaping closure, which means it can refer to implicitly.

You can use the 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 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.

The var is returning a string by accessing the local variable from the class . We cannot directly access the variable. We have to use 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 in the capture list with either a or an 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 , the variable captured becomes optional. Therefore, we should use a to safely unwrap it:

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

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

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

How to capture self with closures with arguments?

Well, you should capture the 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.

Image for post
Image for post
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.

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

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

If you want an autoclosure that is allowed to escape, use both the and attributes.

So, in short,

becomes…..

One more example for explaining autoclosure:

We can create extension on and add something like:

So that,

becomes….

Last , but not the least!!!

Functions and closures are reference types. Here , in the following code, both and refers to the same closure in memory.

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!

Written by

iOS and tvOS developer, dreamer, photographer 🤨

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store