Using closures to simplify
This is an update to an previous post about using blocks to simplify in Objective-C.
Swift makes working with functions much enjoyable simplifying its syntax and, specially, closing the gap between functions, methods and closures. Blocks spread over Objective-C frameworks usually being used as callbacks (completion blocks) for animations or async tasks but they can be used to do a lot more. In Swift we usually see them all over the place, specially with higher order functions like map, filter, etc.
There are a lot of good ways of using functions to add dynamism and generalise your code. Chris Eidhof has some good talks on bending UIKit to a more functional style.
In this post I just want to show you a simple pattern that can be a nice tool to simplify some parts of your code.
The idea is to follow the same pattern as higher order functions do, extracting the customisable part of a task into a function parameter.
The nice example that I find in some UI code is when you have to modify a view in different ways but you want to avoid repeating the common code. You can move this common code in separate methods and chain them every time you need them, but if instead you concentrate the common parts in a single function and extract the customisation in a closure the result is much nicer.
You can use closures to perform some arbitrary code just under some conditions without the need to repeat the code to check those conditions and even without having direct pointers to the needed objects.
func modifyView(customization: (CustomView) -> ()) {
// Check for some conditions
if true {
// Lookup the correct view
CustomView view = ...
// Perform common tasks
// Start animations
...
customization(view)
...
}
}
Usage:
// User taps button A
modifyView {
$0.backgroundColor = UIColor.redColor()
$0.alpha = 0.4
}
// In another place...
modifyView {
$0.alpha = 1
}
// Some notification arrives
modifyView {
// other changes...
}
This is just a made up example of it’s usage but it shows the potential of pulling out customisation points from functions that only perform the common tasks.
Some examples of advantages with this:
- There is no need to keep track of the objects that you need.
- The maintenance of state is in one single place.
- Execute the changes only if a condition is met.
- The customisation can be different on every call site.
- Allows to perform common code easily.
I really like these approach because there is less repeated code (the lookup, the conditions to check, the common things…) and I can focus on writing the code that changes.
This is a simple technique that may seem obvious to experienced programmers, specially coming from functional communities. The best part is that is something that can be used ad-hoc in your code without having to learn new paradigms or use big frameworks.
As with a lot of things in Swift, there is nothing here that couldn’t be done before, but its syntax makes approaches like this more accessible than doing it in Objective-C.