Skip to content

Latest commit

 

History

History
302 lines (195 loc) · 7.88 KB

File metadata and controls

302 lines (195 loc) · 7.88 KB

Closures

Why you should know this

You probably have already used closures by now without noticing 😯

Closures are a powerful way of writing code that performs and looks better.

They are also present in many programming languages so knowing how they work will help you recognize them when working in other type of projects.

Learning Objectives

  1. Describe how closures work and how to use them
  2. Declaring and calling closures
  3. Apply the closure syntax and shorthand argument names

Intro

gifts

Let's say I need to send a gift to a friend. I wrap it in a box and take it to the post office.

After 5 days, it finally arrives to its destination.

My friend can now open the package and reveal their gift.

I'm not there to physically give them the present, but the contents remain in the package until it gets opened and ready to use.

This is the same concept as closures. Let's see how.

What is a Closure?

Apple's definition:

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

In essence, a closure is a block of code that you can assign to a variable or constant. Then pass it around in your code and execute its content later somewhere else

Back to the gift

The actual content of the gift - block of code, something we are going to use later

The wrapped package - the block of code now assigned to a variable

The package gets passed around by the delivery truck - code being passed around

the package being opened and used - Executing the block of code.

Example: closure with statements

var brunch = {
    print("Coffee and bagels")
}
Everything inside the braces `{}` is the closure. And it is assigned to a variable (could be to a constant too).

Q: What is the type of the closure?
We can add it in the declaration.

var brunch: () -> () = {
    print("Coffee and bagels")
}

brunch()

Syntax

syntax

Example: closure with parameters

let brunchOption:(String) -> () = { option in
    print(option)
}
brunchOption("Mimosas and croissants")

Q: What is the type of the closure?

We can use the value passed inside the statements of the closure by placing a parameter name `option` followed by the `in` keyword.

The in keyword separates the parameter name with the body of the closure.

When calling the closure, since it accepts a String, we pass the string in that moment.

Example: closure that returns a value

let brunchOptionLocation:(String) -> (String) = { option in
    let message = option + " @ Castro St."
    return message
}
let result = brunchOptionLocation("Pancakes and smoothies")
print(result)

Q: What is the meaning of (String) -> (String)?
Q: How are we using option?
Q: How do we return and show the output?

Example: passing a closure as a function parameter

func getBrunch(optionClosure:()->()) {
    print("Going for brunch.")
}

getBrunch(optionClosure: {
    print("Anything edible")
})

Q: What is the output?
Q: Why is the closure statement is not executed?

Function vs Closure

Closures are very similar to functions. In fact, functions are a special type of closures. They have a name and are declared with the keyword func whereas closures are nameless.

Take the following function and turn it into a closure. Note each step you make in the transformation. Include how you would call it.

func add(number1: Int, number2: Int) -> Int {
 return number1 + number2
}
Once everyone is done, do the transformation in a big whiteboard for everyone to see and share their insights.

Capturing values

func cook() -> (String) -> Void {
    return {
        print("I'm going to cook \($0)")
    }
}

let result = cook()
result("pizza")
func cook() -> (String) -> Void {
    var counter = 1
    return {
        print("\(counter). I'm going to cook \($0)")
        counter += 1
    }
}

let result = cook()
result("pizza")
result("pasta")
result("cake")

Optimizing with closures

Swift’s closure expressions have a clean, clear style, with optimizations including:

  • Inferring parameters
  • Implicit returns from single-expression closures
  • Shorthand argument names

We'll use the sort method as an example.

sorted(by:) sorts an array of values of a known type, based on the output of a sorting closure that we provide.

Once it completes the sorting process, the sorted(by:) method returns a new array of the same type and size as the old one, with its elements in the correct sorted order.

The original array is not modified.

let names = ["Andrea", "Chris", "Marie", "Beth", "Tom"]

The sorted(by:) method accepts a closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.

First approach, using a function and passing it as a parameter.

func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversedNames = names.sorted(by: backward)

For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter "B" is “greater than” the letter "A".

Second approach, using a closure expression syntax.

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

Since the body of the closure is short, we can write in in one line.

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

Also, because the sorting closure is passed as an argument to a method, Swift can infer the types of its parameters and the type of the value it returns.

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

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

reversedNames = names.sorted(by: { $0 > $1 } )

Challenges

Complete these challenges on closures.

Wrap Up

  • Complete challenges
  • Read the content listed below if you need more clarity on closures.
  • Go over this playground if you feel like wanting more practice with closures.

Additional Resources

  1. Closures in Swift - an article
  2. From function to closure - article
  3. Apple's documentation on closures
  4. Closures explained & exercises
  5. Capturing values