0Pricing
Swift Academy · Lesson

Closures

Closures

Closures is a free Swift Academy lesson on CoddyKit — lesson 1 of 1. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 1 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Introduction

Hello,

Closures are self-contained blocks of code. A closure is passed as a parameter to the code, or it can be used inside codes.

The closure is a type of function. It can be used by passing within the code. They are similar to lambdas in other programming languages.

memory management

One of the most important points is that Closure can store the values ​​of constant and variables in the context it is defined.

This storage is known as closing-over.

Swift does the memory management during this storage for us.

Closure types

There are types of closures.

  1. Global functions are named closures. And these functions do not hold any value.
  2. Nested functions can carry the values ​​of the name and the function wrapped in it.
  3. Closure Expression, on the other hand, is an anonymous closure and can store data from the context that surrounds itself with a simple syntax.

Closure syntax

The syntax of the closures is tried to be simplified as much as possible. The most important of these are as follows.

  • Parameters in closures can be inferred.
  • Return values ​​can be inferred.
  • Closed return can be made in one line.
  • Argument names can be expressed as shortcuts such as $ 0 or $ 1.
  • Trailing closure syntax can be used.

Info

Closure expressions mean writing closures inline, with a focus on syntax and simplicity.

closure syntax

A closure syntax is shown in the sample code below.

{ (parameters) -> return type in
    statements
}


func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.

var reversedNames = names.sorted(by: backward)

closure syntax

However, with Closure, we don't need to define an unnecessarily named global named closure of this type.

It is sufficient to define a simple Closure expression in the parameter. Let's look at the example.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

///sorted method takes closure as parameter.

in keyword

It is understood from the in keyword that the body of the Closure begins.

Before starting the in keyword, the parameters received by the closure and the return type must be defined.

infer type from context

Deriving Types from Context

In the above example, the Closure expression can be understood by inferring the parameters and the return type, since the sorted method comes as a closure.

Therefore, we do not have to define them as extra.

In this example, it will be understood that since the values ​​in the names array are Strings, the parameters received by the closure will be of the String type.

Likewise, the related closure will need a Bool type to sort, so the return type will infer as Bool.

example

This will simplify the usage below.

The arrow can also be omitted from the code by inferring the return type.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

short syntax

Using long syntax instead of short syntax is preferable to avoid confusing code readers.

The above syntax can be shortened even more.

The return value can be shortened with the closed expression by removing the return keyword.

/*
In this example, the return keyword has been extracted.
It already has single expression. 
There is no need to express it as an extra with return.
*/

var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)

example

In this example, the return keyword has been omitted.

There is already a single expression, and there is no need to express it as an extra with the return.

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

name shortcut

The syntax can be shortened even more. In the above example, we stated that the closure takes two parameters. (including s1 and s2) Their types are inferred.

Now we can save the trouble of expressing these parameters with shortcuts and defining them as well.

In addition, since there is no parameter definition and return value passing, the in keyword can also be omitted.

let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)

// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.

shorten example

var names = ["Coddy", "Kit"]

let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.

TRAILING CLOSURE

Trailing Closure

If the parameter to be passed to a closure function is the final argument of the function and the closure expression is long, it may be more useful to write it as a Trailing Closure statement.

We can use the trailing closure as a syntax sugar. Used to increase the readability of the code.

The last parameter of most iOS methods is closure.

fınal parameter

For example, in this example, the final parameter is closure.

class Animator {
    class func animate(withDuration duration: Double, animations: () -> Void) {
        animations()
    }
}

class MyViewController {
    func start() {
        // With the traditional method, we can call this fund as follows.
        Animator.animate(withDuration: 1, animations: { [unowned self] in
            print("red")
        })
    }
}
MyViewController().start()

Since the above code is less legible, it can be written as follows.

Since the above code is less legible, it can be written as follows.

import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")

example

When using Trailing Closure syntax, we don't have to write an argument label.

Because closures have now become a part of the formulation call.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

syntax

We can actually think of the trailing closure syntax as a syntax sugar. It makes the code more readable.

/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)

// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
    self.view.backgroundColor = UIColor.red
})

/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method 
is closure, Swift allows to make a call like the one below.
*/

UIView.animate(withDuration: 1) { [unowned self] in
    self.view.backgroundColor = UIColor.red
}

We can use the code below to test the code

We can use the code below to test the code.


func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}

greetThenRunClosure(name: "Paul") {
    print("The closure was run")
}

Closure Capturing Values

Closure Capturing Values

It can hold the value of variables that enclose a closure environment. You can even change the value of these variables from within its own body and have access.

Even if it's not in the original scope in which these variables were defined.

const.

Generally, he said that he can keep this data in nested functions together with Cloresure expressions. They can store the data of the outer function.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)

print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30

cont.

If you assign a closure as a class property, it will now start holding the membranes of this instance to closure.

Therefore, a strong reference cycle will be established between closure and instance.

Particular attention should be paid to memory leaks.

warning

Closure and Functions are reference types.

@escaping

We may need this usage at many points where the closure is used asynchronously.

In early versions of swift (1 and 2), the closures in swift parameters were escaping and later became non-escaping. If we needed to pass the closure non escaping, we had to specifically specify it.

In the next versions, the closure parameters have been made non-escaping in order to gain an advantage in terms of memory usage.

Now if we want to define a closure escaping we have to bypass the @escaping keyword.

@ESCAPING Keywordu

@ESCAPING Keyword

If we want to be able to call the closures assigned to a function after the function return, we need to appear with the @escaping keyword.

The closures that are defined by default to a function are reference types, but they do not increment the reference count. Because at the moment of call, the heat of this closure ends, and we do not need to increase the reference count as extra.

However, if we need the closure we are looking for as a paramere after a function is called, we may need to express it with the @escaping keyword.

nonEscaping

First, let's see how nonEscaping closure works.

When this closure is passed as a parameter to the function, the closure is processed in the body of the function and then returns to the compiler.

And after the function returns, that is, after the execution is completed, it remains out of the closure scope and is returned to memory.

Using Escaping Closure

Using Escaping Closure

When a closure function is passed as an argument, it continues to be maintained even if the closure function returns and execution is completed.

And it takes up space in memory. Until the closure is executed. There are multiple types of escaping closures.

Congratulations

Congratulations 🎉

We have come to the end of our lesson. 

See you in the next lesson 😎

Closures — illustration 29

Frequently asked questions

Is the “Closures” lesson free?

Yes — the full text of “Closures” is free to read here on the web, and the Swift Academy course includes 1 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Closures”?

Closures You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 1, so you can start here or from the beginning and move at your own pace.

How long does the “Closures” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

← Back to Swift Academy