Swift — Leveraging the power of first-class functions
--
Functions, in Swift, are first-class citizens that can be passed as arguments, stored in properties or returned from functions.
When dealing with Swift built-in functions such as `map` and `forEach`, one often ends up using the trailing closure syntax to provide with the required behavior.
let stackView = UIStackView()
let views = [UIView(), UIView(), UIView()]views.forEach { view in
stackView.addArrangedSubview(view)
}
Or, using the $ syntax:
views.forEach {
stackView.addArrangedSubview($0)
}
While the above implementation is quite clear, let’s see how we can leverage the power of first-class functions and improve code readability.
— Functions
First, let’s take a closer look at the `forEach` expected function argument when looping over our views.
(body: (UIView) throws -> Void)
It expects a function that takes a `UIView` as as argument and returns `Void`.
Now, let’s look at the `addArrangedSubview` function from the Swift documentation.
func addArrangedSubview(_ view: UIView) -> Void
Interestingly enough, the `addArrangedSubview` method gives us exactly what we need to meet the `forEach` argument expectation giving us the ability to directly pass the `addArrangedSubview` into the `forEach` function.
views.forEach(stackView.addArrangedSubview(_:))
The wildcard function argument is not necessary since the compiler can figure on its own what method it refers to.
views.forEach(stackView.addArrangedSubview)
It provides with a shorter syntax while enhancing readability on a code that could almost be read as plain English text.
Let’s wrap it up by removing our subviews from our `UIStackView`.
views.forEach(stackView.removeArrangedSubview)
— Initializers
Since `initializers` are also functions that takes a certain amount of arguments and returns the object they’re defined in, it becomes quite convenient to use such declarative syntax to write more legible code.
let imageStrNames = ["flower", "car", "boat"]imageStrNames
.map(UIImage.init(named:))
.map(UIImageView.init)
.forEach(stackView.addArrangedSubview)
Notice how in the first `map`, we explicitly specify the argument label to give the compiler a hint on which `init` method we want to use (since a `UIImage` has several initializers, it could otherwise lead to misbehaviors).
struct Student {
let name: String
}let studentNames = ["John", "Bob", "Peter"]
let students = studentNames.map(Student.init(name:))
Again, the compiler is smart enough to use the proper initializer so the explicit init argument `name` is not required.
let students = studentNames.map(Student.init)
Follow me on Twitter for my latest articles.