Articles, podcasts and news about Swift development, by John Sundell.

Swift clip: First class functions

Published on 16 Jan 2020

Welcome to Swift Clips — a new series of shorter videos showcasing interesting and useful Swift tips and techniques. In this first episode we’ll take a look at first class functions, which is a language feature that enables us to use functions in really powerful ways.

Genius Scan SDK

Genius Scan SDK: Add a powerful document scanner to any iOS app. Genius Scan’s SDK features advanced image processing that’s the result of over 10 years of research and development and can be fully customized and integrated into your app with just one line of code. Mention Swift by Sundell when requesting a free demo to get a 20% discount on your license for a whole year.

Sample code

Adding a series of views as subviews of another view:

let view: UIView = ...
let subviews: [UIView] = [button, label, imageView]

// Using a closure
subviews.forEach { subview in
    view.addSubview(subview)
}

// Using first class functions
subviews.forEach(view.addSubview)

Converting an array of strings into URL values:

let strings = ["swiftbysundell.com", "apple.com"]

// Using a closure
let urls = strings.compactMap { string in
    URL(string: string)
}

// Using first class functions
let urls = strings.compactMap(URL.init)

Sorting an array of Int values in descending order:

let scores: [Int] = [9, 20, 2, 1, 5]

// Using a closure
let highScores = scores.sorted(by: { $0 > $1 })

// Using first class functions
let highScores = scores.sorted(by: >)

Applying a value to a closure, to avoid the classic “weak self dance”:

// A view controller that currently captures 'self' weakly, in
// order to call a method on a 'productManager' property object:
class ProductViewController: UIViewController {
    ...

    override func viewDidLoad() {
        super.viewDidLoad()

        buyButton.handler = { [weak self] in
            guard let self = self else {
                return
            }

            self.productManager.startCheckout(for: self.product)
        }
    }
}

// Introducing a 'combine' function for applying a value to
// any function or closure:
func combine<A, B>(
    _ value: A,
    with closure: @escaping (A) -> B
) -> () -> B {
    return { closure(value) }
}

// Using our new combine function:
class ProductViewController: UIViewController {
    ...

    override func viewDidLoad() {
        super.viewDidLoad()
        
        buyButton.handler = combine(product,
            with: productManager.startCheckout
        )
    }
}