Weekly Swift articles, podcasts and tips 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.

Architecting SwiftUI apps with MVC and MVVM

This ad keeps all of Swift by Sundell free for everyone. If you can, please check this sponsor out, as that directly helps support this site:

Architecting SwiftUI apps with MVC and MVVM

Architecting SwiftUI apps with MVC and MVVM: Although you can create an app simply by throwing some code together, without best practices and a robust architecture, you’ll soon end up with unmanageable spaghetti code. Learn how to create solid and maintainable apps with fewer bugs using this free guide.

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
        )
    }
}