100 Days of SwiftUI – Day 9

ยท

This one was all about closures

How to create and use closures

Passing function by reference

func greetUser() {
    print("Hi there!")
}

greetUser()

// or get a copy

var greetCopy = greetUser
greetCopy()

Assign function directly to a variable

let sayHello = {
    print("Hi there!")
}

sayHello()

How to write a closure.

let sayHello = { (name:String) -> String in
   "Hi \(name)!"
}

Note

– we don’t use parameter names when calling a closure

func greetUser() {
    print("Hi there!")
}

greetUser()

// rewritten
var greetCopy: () -> Void = greetUser
greetCopy()

Scored 12/12 on Creating basic closures
Scored 7/12 on Accepting Parameters in a closure
Scored 10/12 on Returning Values from a closure

How to use trailing closures and shorthand syntax

Note: Just drop the argument types, and the return type

// You can also remove more clutter by getting rid of the 
// closure's parameter name and the () around it

// So this:
let sorted = t.sorted(be: { a, b in
    if a == "Suzanne" {
        return true
    } else if b == "Suzanne" {
        return false
    }

    return a < b
})

// Turns to:
let sorted = t.sorted { a, b in
    if a == "Suzanne" {
        return true
    } else if b == "Suzanne" {
        return false
    }

    return a < b
}

Swift automatically provides parameter names for us, using shorthand syntax.

// So this:
let sorted = t.sorted { a, b in
    if a == "Suzanne" {
        return true
    } else if b == "Suzanne" {
        return false
    }

    return a < b
}

// Turns to:
let sorted = t.sorted {
    if $0 == "Suzanne" {
        return true
    } else if $1 == "Suzanne" {
        return false
    }

    return $0 < $1
}

Everything in the parameters is part of the function body.

The reverse sort example provided is simpler (meaning no branching as in the previous examples) and shows how the function could be made even more concise.

// Starting with:
let reverseSort = t.sorted {
    return $0 > $1
}
// can remove the return
let reverseSort = t.sorted {
    $0 > $1
}

let reverseSort = t.sorted { $0 > $1 }

When its best to not do it:

  • The closure’s code is too long
  • the provided parameters $0 are used more than once
  • You have 3 or more parameters

More examples

let tOnly = t.filter { $0.hasPrefix("T") }

let mappedVals = t.map { $0.uppercased() }

Scored 6/6 on Shorthand parameter names

How to accept functions as parameters

// Example

func ma(size: Int, using generator: () -> Int) -> [Int] {

    var numbers = [Int]()

    for _ in 0..<size {
        // use the passed in function to generate an integer
        let newNum = generator()
        numbers.append(newNum)
    }

    return numbers
}

// Another
func genNewNum() -> Int {
    Int.random(in: 1...20)
}

let newRolls = ma(size: 50, using: genNewNum)

Functions can accept multiple functions as parameters.

We can do this:

func doImpWork(first: () -> Void, second: () -> Void, third: () -> Void) -> Void {
    // doing the first thing
    first()
    // doing the second thing
    second()
    // doing the third thing
    third()
}

or we can do this:

doImpWork {
    // first thing gets done
} second: {
    // second thing gets done
} third: {
    // third thing gets done
}

Scored 11/12 on Closures as parameters.
Scored 11/12 on Trailing closure syntax.

Summary

  • You can copy functions, the copy loses its parameter name
  • All functions have types, their parameters have types and their returns have a type.
  • A closure can be assigned to a variable or a constant
  • Closure parameters are inside the function body followed by the word in
  • Functions can accept functions as parameters
  • You can pass a dedicated function or a closure
  • You don’t need to write the types of the parameters if Swift can figure it out
  • If one or more parameters of a function are functions, you can use trailing closure syntax.
  • Shorthand parameters like $0 and $1 work but mainly under conditions
  • Its more important to know how to use this than how to create it

Currently
Building

1 product