- Sometimes the only way to influence the common
state
of thecode base
make major changes, such as changing the code architecture, changing the way data is transmitted, or applying newframework
. - In this article, we’ll look at how to write small
utility functions
that make common tasks easier with simplerpattern
to use.
1 / Configuration closures:
- Part of the code in projects is dedicated to identifying certain
object
to use. Especially when usingobject orient
UI like UIKit. Just as we have gone through Encapsulating configuration code in Swift , finding neat ways to write separate code can improve the transparency of the logic as well as the extent to which the code is used. - For example, we are using the common
pattern
using self-executing closures as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">class</span> <span class="token class-name">HeaderView</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> imageView <span class="token punctuation">:</span> <span class="token builtin">UIImageView</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token function">UIImageView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> view <span class="token punctuation">.</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> view <span class="token punctuation">.</span> contentMode <span class="token operator">=</span> <span class="token punctuation">.</span> scaleAspectFit view <span class="token punctuation">.</span> image <span class="token operator">=</span> <span class="token punctuation">.</span> placeholder <span class="token keyword">return</span> view <span class="token punctuation">}</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">let</span> label <span class="token punctuation">:</span> <span class="token builtin">UILabel</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token function">UILabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> view <span class="token punctuation">.</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> view <span class="token punctuation">.</span> numberOfLines <span class="token operator">=</span> <span class="token number">2</span> view <span class="token punctuation">.</span> font <span class="token operator">=</span> <span class="token punctuation">.</span> <span class="token function">preferredFont</span> <span class="token punctuation">(</span> forTextStyle <span class="token punctuation">:</span> <span class="token punctuation">.</span> headline <span class="token punctuation">)</span> <span class="token keyword">return</span> view <span class="token punctuation">}</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
- There is nothing wrong with the above code, but it is better if we can reduce the amount of code associated with each
property
. There are a number of different approaches we can take here such as using factory methods instead ofself-executing closures
let’s see if we can write asimple utility funtion
to help uscode
It is more compact while still using the samepattern
. - Introduce to you the function called
configure
, it will take a value that we want toconfigure
andclosure
to do the jobconfigure
it. We can encapsulate all of ourconfigure
code and also pass a remote parameter with theinout
keyword that allows our new function to be used with value types:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">func</span> configure <span class="token operator"><</span> T <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token number">_</span> value <span class="token punctuation">:</span> T <span class="token punctuation">,</span> using closure <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token keyword">inout</span> T <span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">Void</span> <span class="token punctuation">)</span> <span class="token keyword">rethrows</span> <span class="token operator">-</span> <span class="token operator">></span> T <span class="token punctuation">{</span> <span class="token keyword">var</span> value <span class="token operator">=</span> value <span class="token keyword">try</span> <span class="token function">closure</span> <span class="token punctuation">(</span> <span class="token operator">&</span> value <span class="token punctuation">)</span> <span class="token keyword">return</span> value <span class="token punctuation">}</span> |
- Now we can go back to our
HeaderView
and make theconfigure
codesubview
more readable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">class</span> <span class="token class-name">HeaderView</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> imageView <span class="token operator">=</span> <span class="token function">configure</span> <span class="token punctuation">(</span> <span class="token function">UIImageView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> contentMode <span class="token operator">=</span> <span class="token punctuation">.</span> scaleAspectFit $ <span class="token number">0</span> <span class="token punctuation">.</span> image <span class="token operator">=</span> <span class="token punctuation">.</span> placeholder <span class="token punctuation">}</span> <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token function">configure</span> <span class="token punctuation">(</span> <span class="token function">UILabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> numberOfLines <span class="token operator">=</span> <span class="token number">2</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> font <span class="token operator">=</span> <span class="token punctuation">.</span> <span class="token function">preferredFont</span> <span class="token punctuation">(</span> forTextStyle <span class="token punctuation">:</span> <span class="token punctuation">.</span> headline <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
- One advantage of our
configure
code function is that it can be used with anytype
fromUIView
to any type ofobject
. - For example, we use the same
pattern
as above when setting theURLRequest
value to be used to synchronize data when users are connected to WiFi:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">struct</span> <span class="token builtin">SyncNetworkTask</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token function">configure</span> <span class="token punctuation">(</span> <span class="token function">URLRequest</span> <span class="token punctuation">(</span> url <span class="token punctuation">:</span> <span class="token punctuation">.</span> syncEndpoint <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> httpMethod <span class="token operator">=</span> <span class="token string">"PATCH"</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> <span class="token function">addValue</span> <span class="token punctuation">(</span> <span class="token string">"application/json"</span> <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token string">"Content-Type"</span> <span class="token punctuation">)</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> allowsCellularAccess <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
2 / Rethrowing functions:
- One detail of the above function that can easily be missed is that it is marked with the keyword
rethrow
. What keywords do is to tell the compilerSwift
only as functions thatthrow
if theclosure
is passed to it as wellthrow
.
1 2 3 4 5 6 | <span class="token keyword">let</span> webView <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token function">configure</span> <span class="token punctuation">(</span> <span class="token function">WKWebView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> html <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token function">loadBundledHTML</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">try</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> <span class="token function">loadHTMLString</span> <span class="token punctuation">(</span> html <span class="token punctuation">,</span> baseURL <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> |
- Whenever we design any
AP
I that acceptssynchronous closures
, we should definitely consider marking our functions with re-access times that allow us tothrow error
when needed.
3 / Reducing boilerplate:
- Besides specifying
code convention
utility function
can also help us avoid common errors such as performing more specific tasks, such as defininglayout
andcolor
.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token function">UILabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> label <span class="token punctuation">.</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> view <span class="token punctuation">.</span> <span class="token function">addSubview</span> <span class="token punctuation">(</span> label <span class="token punctuation">)</span> <span class="token builtin">NSLayoutConstraint</span> <span class="token punctuation">.</span> <span class="token function">activate</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> label <span class="token punctuation">.</span> topAnchor <span class="token punctuation">.</span> <span class="token function">constraint</span> <span class="token punctuation">(</span> equalTo <span class="token punctuation">:</span> view <span class="token punctuation">.</span> topAnchor <span class="token punctuation">)</span> <span class="token punctuation">,</span> label <span class="token punctuation">.</span> leadingAnchor <span class="token punctuation">.</span> <span class="token function">constraint</span> <span class="token punctuation">(</span> equalTo <span class="token punctuation">:</span> view <span class="token punctuation">.</span> leadingAnchor <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> |
- We can choose something as simple as the
extension UIView
automatically prepares the given view for use withauto layout
then activates a range ofconstraint
:
1 2 3 4 5 6 7 | <span class="token keyword">extension</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">layout</span> <span class="token punctuation">(</span> using constraints <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token builtin">NSLayoutConstraint</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token builtin">NSLayoutConstraint</span> <span class="token punctuation">.</span> <span class="token function">activate</span> <span class="token punctuation">(</span> constraints <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- With just that small
extension
, we can really make oursource code
more readable:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token function">UILabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> view <span class="token punctuation">.</span> <span class="token function">addSubview</span> <span class="token punctuation">(</span> label <span class="token punctuation">)</span> label <span class="token punctuation">.</span> <span class="token function">layout</span> <span class="token punctuation">(</span> using <span class="token punctuation">:</span> <span class="token punctuation">[</span> label <span class="token punctuation">.</span> topAnchor <span class="token punctuation">.</span> <span class="token function">constraint</span> <span class="token punctuation">(</span> equalTo <span class="token punctuation">:</span> view <span class="token punctuation">.</span> topAnchor <span class="token punctuation">)</span> <span class="token punctuation">,</span> label <span class="token punctuation">.</span> leadingAnchor <span class="token punctuation">.</span> <span class="token function">constraint</span> <span class="token punctuation">(</span> equalTo <span class="token punctuation">:</span> view <span class="token punctuation">.</span> leadingAnchor <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> |
- Let’s look at another example we looked at to easily identify
dynamic coloe
adapting to whether the user’s device is currently running inlight mode
ordark mode
:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">let</span> backgroundColor <span class="token operator">=</span> <span class="token builtin">UIColor</span> <span class="token punctuation">{</span> traitCollection <span class="token keyword">in</span> <span class="token keyword">switch</span> traitCollection <span class="token punctuation">.</span> userInterfaceStyle <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> dark <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">UIColor</span> <span class="token punctuation">(</span> white <span class="token punctuation">:</span> <span class="token number">0.15</span> <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> light <span class="token punctuation">,</span> <span class="token punctuation">.</span> unspecified <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">UIColor</span> <span class="token punctuation">(</span> white <span class="token punctuation">:</span> <span class="token number">0.85</span> <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- We are trying to determine which color pairs to use in
light mode
ordark mode
. Name our newcolorPair
function and let it accept aUIColor
to use for slight mode
ordark mode
. We will then call theUIColor
API to return the appropriate color for eachUIUserInterfaceStyle
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">func</span> <span class="token function">colorPair</span> <span class="token punctuation">(</span> light <span class="token punctuation">:</span> <span class="token builtin">UIColor</span> <span class="token punctuation">,</span> dark <span class="token punctuation">:</span> <span class="token builtin">UIColor</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIColor</span> <span class="token punctuation">{</span> <span class="token builtin">UIColor</span> <span class="token punctuation">{</span> traitCollection <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIColor</span> <span class="token keyword">in</span> <span class="token keyword">switch</span> traitCollection <span class="token punctuation">.</span> userInterfaceStyle <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> dark <span class="token punctuation">:</span> <span class="token keyword">return</span> dark <span class="token keyword">case</span> <span class="token punctuation">.</span> light <span class="token punctuation">,</span> <span class="token punctuation">.</span> unspecified <span class="token punctuation">:</span> <span class="token keyword">return</span> light <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- We declare our
backgroundColor
above as follows:
1 2 3 4 5 | <span class="token keyword">let</span> backgroundColor <span class="token operator">=</span> <span class="token function">colorPair</span> <span class="token punctuation">(</span> light <span class="token punctuation">:</span> <span class="token function">UIColor</span> <span class="token punctuation">(</span> white <span class="token punctuation">:</span> <span class="token number">0.85</span> <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> dark <span class="token punctuation">:</span> <span class="token function">UIColor</span> <span class="token punctuation">(</span> white <span class="token punctuation">:</span> <span class="token number">0.15</span> <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
- Combining the above feature with another
utility function
allows us to identify anyUIColor
using the dot syntax:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">extension</span> <span class="token builtin">UIColor</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">grayScale</span> <span class="token punctuation">(</span> <span class="token number">_</span> white <span class="token punctuation">:</span> <span class="token builtin">CGFloat</span> <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> <span class="token builtin">CGFloat</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIColor</span> <span class="token punctuation">{</span> <span class="token function">UIColor</span> <span class="token punctuation">(</span> white <span class="token punctuation">:</span> white <span class="token punctuation">,</span> alpha <span class="token punctuation">:</span> alpha <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> backgroundColor <span class="token operator">=</span> <span class="token function">colorPair</span> <span class="token punctuation">(</span> light <span class="token punctuation">:</span> <span class="token punctuation">.</span> <span class="token function">grayScale</span> <span class="token punctuation">(</span> <span class="token number">0.85</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> dark <span class="token punctuation">:</span> <span class="token punctuation">.</span> <span class="token function">grayScale</span> <span class="token punctuation">(</span> <span class="token number">0.15</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
- While writing
utility function
like the above, we may ask ourselves questions like why are the defaultAPI
designed this way? As with almost everything in programming – great APIs are often about balancing a certain set of tradeoffs.