unpredictable.tech2021-09-16T13:30:34+00:00https://unpredictable.tech/Victor PavlychkoPrivate APIs, Objective-C runtime, and Swift2020-09-08T00:00:00+00:00https://unpredictable.tech/2020/09/08/private-apis-objective-c-runtime-and-swift/<p>Sometimes when building an app, we find ourselves in a situation when we want to use a private API.
It may provide some important functionality that is not exposed (yet), or we may want to work around
a known platform issue. Or, you may be just debugging your code and poking around to get extra details.</p>
<!-- more -->
<blockquote>
<p>Whatever you are trying to achieve, keep in mind that private APIs are fragile and can change without
notice, leaving you with a broken product and frustrated users.</p>
</blockquote>
<p>Swift adds another dimension here: restricted APIs marked as
<a href="https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/making_objective-c_apis_unavailable_in_swift"><code class="language-plaintext highlighter-rouge">NS_SWIFT_UNAVAILABLE</code></a>.
Those are not technically private, but they are considered not safe enough and thus are not exposed in Swift.
Calling into such unavailable APIs is pretty ok as they are fully documented and accessible from
Objective-C code. This post will focus on accessing a group of Swift-unavailable APIs related to dynamic
message dispatch provided by
<a href="https://developer.apple.com/documentation/foundation/nsmethodsignature"><code class="language-plaintext highlighter-rouge">NSMethodSignature</code></a>,
<a href="https://developer.apple.com/documentation/foundation/nsinvocation"><code class="language-plaintext highlighter-rouge">NSInvocation</code></a>,
and <a href="https://developer.apple.com/documentation/objectivec/nsobject/1571960-methodsignatureforselector?language=objc"><code class="language-plaintext highlighter-rouge">NSObject</code></a>
classes. I encourage you to check the documentation if you are not familiar with those.</p>
<p>Nothing is private as long as Objective-C runtime is involved. Things have changed slightly with
the introduction of direct methods. Still, a lot of APIs remain accessible if you know how to
invoke them.</p>
<h2 id="invoking-private-apis-from-swift">Invoking private APIs from Swift</h2>
<p>But how do you call a method that is not exposed by the SDK? Back in the Objective-C days, everything
was easy — thanks to the language’s dynamic nature, you could declare a category with any private methods.
They would automatically resolve at runtime.</p>
<p>Swift is a type-safe language, and you no longer allowed to do that. Common approaches rely on
Swift-compatible Foundation APIs like
<a href="https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418867-perform"><code class="language-plaintext highlighter-rouge">perform(_:)</code></a>
for simple functions or low-level
<a href="https://developer.apple.com/documentation/objectivec/1418551-method_getimplementation"><code class="language-plaintext highlighter-rouge">method_getImplementation</code></a>
and/or
<a href="https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend"><code class="language-plaintext highlighter-rouge">objc_msgSend</code></a>
when dealing with more sophisticated signatures. Unfortunately, this results in
complicated, verbose, and error-prone code.</p>
<p>Can we do something better? While the original category-based approach is not available in Swift, we
can try something similar — we are still calling into Objective-C.</p>
<h3 id="a-cleaner-approach">A cleaner approach</h3>
<p>The idea is analogous to the category trick we did previously: we can define an <code class="language-plaintext highlighter-rouge">@objc</code> protocol containing
methods of interest, use the runtime to add conformance to the class in question retroactively, and
then ask Swift to do the typecast. Thanks to the dynamic dispatch used in everything coming from the
Objective-C world, the protocol will be implemented automatically by existing class methods we are
looking for.</p>
<p>To get started, we will define a protocol for <code class="language-plaintext highlighter-rouge">NSMethodSignature</code> matching what we can see in
the Objective-C documentation. Notice the <code class="language-plaintext highlighter-rouge">@objc(getArgumentTypeAtIndex:)</code> annotation I used here.
Normally, the compiler will generate the appropriate selector based on the method name, yet we may
want to alter the auto-generated name. Using correct selector names is crucial in our case, where
we have to match underlying API signatures perfectly.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">@objc</span> <span class="kd">protocol</span> <span class="kt">NSMethodSignaturePrivate</span> <span class="p">{</span>
<span class="kd">static</span> <span class="kd">func</span> <span class="nf">signature</span><span class="p">(</span><span class="nv">objCTypes</span><span class="p">:</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CChar</span><span class="o">></span><span class="p">)</span> <span class="o">-></span> <span class="kt">NSMethodSignaturePrivate</span><span class="p">?</span>
<span class="k">var</span> <span class="nv">numberOfArguments</span><span class="p">:</span> <span class="kt">Int</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="kd">@objc</span><span class="p">(</span><span class="nv">getArgumentTypeAtIndex</span><span class="p">:)</span> <span class="kd">func</span> <span class="nf">getArgumentType</span><span class="p">(</span><span class="n">at</span> <span class="nv">index</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CChar</span><span class="o">></span>
<span class="k">var</span> <span class="nv">frameLength</span><span class="p">:</span> <span class="kt">Int</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">isOneway</span><span class="p">:</span> <span class="kt">ObjCBool</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">methodReturnType</span><span class="p">:</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CChar</span><span class="o">></span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">methodReturnLength</span><span class="p">:</span> <span class="kt">Int</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Once we have that protocol, we can attach it with explicit objc runtime calls:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Obtain class reference from runtime:</span>
<span class="kd">let</span> <span class="p">`</span><span class="nv">class</span><span class="p">`</span> <span class="o">=</span> <span class="s">"NSMethodSignature"</span><span class="o">.</span><span class="n">withCString</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">objc_getClass</span><span class="p">(</span><span class="nv">$0</span><span class="p">)</span> <span class="k">as!</span> <span class="kt">AnyClass</span>
<span class="p">}</span>
<span class="c1">// Add protocol conformance:</span>
<span class="nf">class_addProtocol</span><span class="p">(`</span><span class="nv">class</span><span class="p">`,</span> <span class="kt">NSMethodSignaturePrivate</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
<span class="c1">// Get `NSMethodSignaturePrivate.Type` meta-type reference</span>
<span class="k">let</span> <span class="nv">NSMethodSignatureClass</span> <span class="o">=</span> <span class="p">`</span><span class="nv">class</span><span class="p">`</span> <span class="k">as!</span> <span class="kt">NSMethodSignaturePrivate</span><span class="o">.</span><span class="k">Type</span>
</code></pre></div></div>
<p>Whoa, that’s some boilerplate, and we haven’t added any error checks yet — looks like the right
candidate for a helper function. We will fix that right after testing that everything works
as expected.</p>
<p>We will be working with method signatures here, and if you are not familiar with those, I recommend
reading <a href="https://nshipster.com/type-encodings/">an excellent article from NSHipster</a> to learn more
about type encoding in Objective-C. As a quick recap, I’ll remind that <code class="language-plaintext highlighter-rouge">v@:</code> signature stays
for “a method that returns void and accepts two implicit parameters: instance reference and method selector.”</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Call private class function:</span>
<span class="k">let</span> <span class="nv">signature</span> <span class="o">=</span> <span class="s">"v@:"</span><span class="o">.</span><span class="n">withCString</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">NSMethodSignatureClass</span><span class="o">.</span><span class="nf">signature</span><span class="p">(</span><span class="nv">objCTypes</span><span class="p">:</span> <span class="nv">$0</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// Call private instance function:</span>
<span class="nf">print</span><span class="p">(</span><span class="s">"Number of arguments: </span><span class="se">\(</span><span class="n">signature</span><span class="o">!.</span><span class="n">numberOfArguments</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>
<p>As intended, this says, “Number of arguments: 2,” which means that we have successfully constructed
a signature for a method accepting two parameters.</p>
<h3 id="reducing-boilerplate">Reducing boilerplate</h3>
<p>Now back to the class import code. At first, it seems like we can leverage generics in a helper function
to remove protocol reference duplication like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="n">importClass</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">className</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="k">as</span> <span class="nv">protocol</span><span class="p">:</span> <span class="kt">T</span><span class="o">.</span><span class="k">Type</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span><span class="o">.</span><span class="k">Type</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Not implemented yet."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">NSMethodSignatureClass</span> <span class="o">=</span> <span class="nf">importClass</span><span class="p">(</span><span class="s">"NSMethodSignature"</span><span class="p">,</span> <span class="nv">as</span><span class="p">:</span> <span class="kt">NSMethodSignaturePrivate</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">signature</span> <span class="o">=</span> <span class="s">"v@:"</span><span class="o">.</span><span class="nf">withCString</span><span class="p">(</span><span class="kt">NSMethodSignatureClass</span><span class="o">.</span><span class="nf">signature</span><span class="p">(</span><span class="nv">objCTypes</span><span class="p">:))</span>
</code></pre></div></div>
<p>Except this fails to compile, producing an error: “Static member <code class="language-plaintext highlighter-rouge">signature(objCTypes:)</code> cannot be
used on protocol metatype <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.Protocol</code>.”</p>
<p>You see, <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate</code> is a protocol, and thus we need a concrete conforming type to
create an <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.Type</code> value. Because of that, the <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.self</code>
syntax was repurposed to produce an <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.Protocol</code>, which we can use with
runtime functions. But that thing does not allow us to call class functions like
<code class="language-plaintext highlighter-rouge">signature(objCTypes:)</code>.</p>
<p>Let’s give it another try:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="n">importClass</span><span class="o"><</span><span class="kt">ProtocolType</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">className</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">ProtocolType</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Not implemented yet."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">NSMethodSignatureClass</span> <span class="o">=</span> <span class="nf">importClass</span><span class="p">(</span><span class="s">"NSMethodSignature"</span><span class="p">)</span> <span class="k">as</span> <span class="kt">NSMethodSignaturePrivate</span><span class="o">.</span><span class="k">Type</span>
<span class="k">let</span> <span class="nv">signature</span> <span class="o">=</span> <span class="s">"v@:"</span><span class="o">.</span><span class="nf">withCString</span><span class="p">(</span><span class="kt">NSMethodSignatureClass</span><span class="o">.</span><span class="nf">signature</span><span class="p">(</span><span class="nv">objCTypes</span><span class="p">:))</span>
</code></pre></div></div>
<p>Now, this looks better, but how do we get <code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.Protocol</code> from
<code class="language-plaintext highlighter-rouge">NSMethodSignaturePrivate.Type</code>? I haven’t found any clear way to convert between those two,
but we can use the type name as a middle ground here — use Swift reflection API to get the
protocol name and then find it’s runtime counterpart with <code class="language-plaintext highlighter-rouge">objc_getProtocol</code>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="n">importClass</span><span class="o"><</span><span class="kt">ProtocolType</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">className</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">ProtocolType</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">typeNameSuffix</span> <span class="o">=</span> <span class="s">".Type"</span>
<span class="k">let</span> <span class="nv">protocolTypeName</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(</span><span class="nv">reflecting</span><span class="p">:</span> <span class="kt">ProtocolType</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
<span class="k">guard</span> <span class="n">protocolTypeName</span><span class="o">.</span><span class="nf">hasSuffix</span><span class="p">(</span><span class="n">typeNameSuffix</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">preconditionFailure</span><span class="p">(</span><span class="s">"Type `</span><span class="se">\(</span><span class="n">protocolTypeName</span><span class="se">)</span><span class="s">` is not a protocol type."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">protocolName</span> <span class="o">=</span> <span class="n">protocolTypeName</span><span class="o">.</span><span class="nf">dropLast</span><span class="p">(</span><span class="n">typeNameSuffix</span><span class="o">.</span><span class="n">count</span><span class="p">)</span>
<span class="k">guard</span> <span class="kd">let</span> <span class="p">`</span><span class="nv">protocol</span><span class="p">`</span> <span class="o">=</span> <span class="n">protocolName</span><span class="o">.</span><span class="nf">withCString</span><span class="p">(</span><span class="n">objc_getProtocol</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">preconditionFailure</span><span class="p">(</span><span class="s">"Type `</span><span class="se">\(</span><span class="n">protocolName</span><span class="se">)</span><span class="s">` is not an objc protocol."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">guard</span> <span class="kd">let</span> <span class="p">`</span><span class="nv">class</span><span class="p">`</span> <span class="o">=</span> <span class="n">className</span><span class="o">.</span><span class="nf">withCString</span><span class="p">(</span><span class="n">objc_getClass</span><span class="p">)</span> <span class="k">as?</span> <span class="kt">AnyClass</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">preconditionFailure</span><span class="p">(</span><span class="s">"Class `</span><span class="se">\(</span><span class="n">className</span><span class="se">)</span><span class="s">` not found."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">if</span> <span class="o">!</span><span class="nf">class_addProtocol</span><span class="p">(`</span><span class="nv">class</span><span class="p">`,</span> <span class="p">`</span><span class="nv">protocol</span><span class="p">`)</span> <span class="p">{</span>
<span class="nf">assertionFailure</span><span class="p">(</span><span class="s">"Failed to attach protocol `</span><span class="se">\(</span><span class="n">protocolName</span><span class="se">)</span><span class="s">` to class `</span><span class="se">\(</span><span class="n">className</span><span class="se">)</span><span class="s">`."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">result</span> <span class="o">=</span> <span class="p">`</span><span class="nv">class</span><span class="p">`</span> <span class="k">as?</span> <span class="kt">ProtocolType</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Failed to cast class `</span><span class="se">\(</span><span class="n">className</span><span class="se">)</span><span class="s">` to protocol `</span><span class="se">\(</span><span class="n">protocolName</span><span class="se">)</span><span class="s">`."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">result</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>Objective-C runtime, together with Swift expressiveness, provides a lot of opportunities.
We can access Swift-restricted or private APIs using a little hacking, just like we did
in Objective-C (all safety measures are on us, though):</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">object</span> <span class="o">=</span> <span class="kt">NSDate</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">objectPrivate</span> <span class="o">=</span> <span class="n">object</span> <span class="k">as!</span> <span class="kt">NSObjectPrivate</span>
<span class="k">let</span> <span class="nv">selector</span> <span class="o">=</span> <span class="kt">Selector</span><span class="p">(</span><span class="s">"description"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">signature</span> <span class="o">=</span> <span class="n">objectPrivate</span><span class="o">.</span><span class="nf">methodSignature</span><span class="p">(</span><span class="nv">for</span><span class="p">:</span> <span class="n">selector</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">invocation</span> <span class="o">=</span> <span class="kt">NSInvocationClass</span><span class="o">.</span><span class="nf">invocation</span><span class="p">(</span><span class="nv">methodSignature</span><span class="p">:</span> <span class="n">signature</span><span class="p">)</span>
<span class="n">invocation</span><span class="o">.</span><span class="n">selector</span> <span class="o">=</span> <span class="n">selector</span>
<span class="n">invocation</span><span class="o">.</span><span class="nf">invoke</span><span class="p">(</span><span class="nv">target</span><span class="p">:</span> <span class="n">object</span><span class="p">)</span>
<span class="k">var</span> <span class="nv">unmanagedResult</span><span class="p">:</span> <span class="kt">Unmanaged</span><span class="o"><</span><span class="kt">NSString</span><span class="o">></span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="n">invocation</span><span class="o">.</span><span class="nf">getReturnValue</span><span class="p">(</span><span class="o">&</span><span class="n">unmanagedResult</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">result</span> <span class="o">=</span> <span class="n">unmanagedResult</span><span class="p">?</span><span class="o">.</span><span class="nf">takeRetainedValue</span><span class="p">()</span>
<span class="nf">print</span><span class="p">(</span><span class="n">result</span> <span class="p">??</span> <span class="s">"<nil>"</span><span class="p">)</span>
</code></pre></div></div>
<p>Check this gist for a full example: <a href="https://gist.github.com/victor-pavlychko/8a896917d8c73f4dded594ab4782214e">https://gist.github.com/victor-pavlychko/8a896917d8c73f4dded594ab4782214e</a></p>
Bringing the Best of SwiftUI to Our Team’s UIKit Code2020-05-26T00:00:00+00:00https://www.grammarly.com/blog/engineering/swiftui-uikit/
<p>Like pretty much all our colleagues in the field, iOS developers at Grammarly are excited about SwiftUI. Released at the 2019
Apple Worldwide Developers Conference (WWDC), it represents a major step forward in Apple’s support for building great user
experiences. But as much as we want to use SwiftUI for everything, we can’t. For one thing, the libraries are still new and will
probably take a few years to completely stabilize. Plus, SwiftUI is only bundled in iOS 13+, and we need to continue to support
Grammarly for older versions of iOS. And finally, our existing UIKit code represents a huge, years-long investment for our
team—we don’t want to just throw it out.</p>
<p><a href="https://www.grammarly.com/blog/engineering/swiftui-uikit/">Read more…</a></p>
String Index Type Safety in Swift2019-12-19T00:00:00+00:00https://www.grammarly.com/blog/engineering/string-index-type-safety-in-swift/
<p>Code is much like a conversation, and misunderstandings can happen when assumptions aren’t stated upfront. It brings to mind
a quote (perhaps apocryphal) from the Enlightenment philosopher Voltaire: “If you wish to converse with me, first define your
terms.” Though he is unlikely to have anticipated how this advice might apply to computer science, it rings true when considering
the code development process. Misunderstandings lead to bugs—which our team found out when working with our iOS text
manipulation logic.</p>
<p><a href="https://www.grammarly.com/blog/engineering/string-index-type-safety-in-swift/">Read more…</a></p>
DRY String Localization with Interface Builder2017-08-21T00:00:00+00:00https://unpredictable.tech/2017/08/21/dry-string-localization-with-interface-builder/<p>Great applications should have great localization. And users will appreciate an option to use beloved apps
in their native language. There is no excuse for developers not to support interface localization even on
early stages of the development process, especially when it’s so easy to do.</p>
<p>I prefer to design mostly with the Interface Builder. In this article I would like to share an approach
I use in my projects to localize those resources.</p>
<!-- more -->
<p>Normally, when you try to localize a XIB file or storyboard, Xcode will happily clone the resource and you
get stuck with duplicated view layouts. Yuck… That’s hardly a good option if you are trying to follow
the DRY methodology 😕</p>
<p>Instead of doing that I suggest filling “at”-prefixed localization terms in the Interface Builder and
replacing them with the localized values in <code class="language-plaintext highlighter-rouge">viewDidLoad</code> or <code class="language-plaintext highlighter-rouge">awakeFromNib</code> methods of the corresponding objects.
Here is an example of how it looks like in the Interface Builder:</p>
<p>I use <code class="language-plaintext highlighter-rouge">@</code> prefix for localization terms to allow mixing them with any real values as needed. Additionally,
leading <code class="language-plaintext highlighter-rouge">@@</code> sequence is replaced with a single <code class="language-plaintext highlighter-rouge">@</code> in case you need to specify unlocalized string starting
with the “at” symbol.</p>
<p>As it usually happens in Swift, we start with a protocol:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Followed by an extension containing some helpers to localize strings and apply localized values to properties:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">String</span><span class="p">?</span> <span class="p">{</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">term</span> <span class="o">=</span> <span class="n">string</span><span class="p">,</span> <span class="n">term</span><span class="o">.</span><span class="nf">hasPrefix</span><span class="p">(</span><span class="s">"@"</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">string</span>
<span class="p">}</span>
<span class="k">guard</span> <span class="o">!</span><span class="n">term</span><span class="o">.</span><span class="nf">hasPrefix</span><span class="p">(</span><span class="s">"@@"</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">term</span><span class="o">.</span><span class="nf">substring</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">term</span><span class="o">.</span><span class="nf">index</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="n">term</span><span class="o">.</span><span class="n">startIndex</span><span class="p">))</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kt">NSLocalizedString</span><span class="p">(</span><span class="n">term</span><span class="o">.</span><span class="nf">substring</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">term</span><span class="o">.</span><span class="nf">index</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="n">term</span><span class="o">.</span><span class="n">startIndex</span><span class="p">)),</span> <span class="nv">comment</span><span class="p">:</span> <span class="s">""</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">?,</span> <span class="n">_</span> <span class="nv">setter</span><span class="p">:</span> <span class="p">(</span><span class="kt">String</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">setter</span><span class="p">(</span><span class="nf">localize</span><span class="p">(</span><span class="n">string</span><span class="p">))</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">(</span><span class="n">_</span> <span class="nv">getter</span><span class="p">:</span> <span class="p">(</span><span class="kt">UIControlState</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span><span class="p">?,</span> <span class="n">_</span> <span class="nv">setter</span><span class="p">:</span> <span class="p">(</span><span class="kt">String</span><span class="p">?,</span> <span class="kt">UIControlState</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">setter</span><span class="p">(</span><span class="nf">localize</span><span class="p">(</span><span class="nf">getter</span><span class="p">(</span><span class="o">.</span><span class="n">normal</span><span class="p">)),</span> <span class="o">.</span><span class="n">normal</span><span class="p">)</span>
<span class="nf">setter</span><span class="p">(</span><span class="nf">localize</span><span class="p">(</span><span class="nf">getter</span><span class="p">(</span><span class="o">.</span><span class="n">selected</span><span class="p">)),</span> <span class="o">.</span><span class="n">selected</span><span class="p">)</span>
<span class="nf">setter</span><span class="p">(</span><span class="nf">localize</span><span class="p">(</span><span class="nf">getter</span><span class="p">(</span><span class="o">.</span><span class="n">highlighted</span><span class="p">)),</span> <span class="o">.</span><span class="n">highlighted</span><span class="p">)</span>
<span class="nf">setter</span><span class="p">(</span><span class="nf">localize</span><span class="p">(</span><span class="nf">getter</span><span class="p">(</span><span class="o">.</span><span class="n">disabled</span><span class="p">)),</span> <span class="o">.</span><span class="n">disabled</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p><strong>Note:</strong> <code class="language-plaintext highlighter-rouge">substring</code> API is deprecated in Swift 4, should be replaced with <code class="language-plaintext highlighter-rouge">dropFirst</code> which also describes
the original intent better.</p>
</blockquote>
<blockquote>
<p><strong>Note:</strong> second localization helper should be upgraded to use the new KeyPath syntax when moving
to Swift 4.</p>
</blockquote>
<p>Ok, so far, so good. Now let’s start implementing some localization. The process itself is clearly recursive
where each container asks its children to localize themselves:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UIView</span><span class="p">:</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="n">subviews</span><span class="o">.</span><span class="n">forEach</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Having implemented that, let’s add localization support for common controls required in most applications.
The implementation is straightforward:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UILabel</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">override</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="nf">localize</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="p">{</span> <span class="n">text</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UIButton</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">override</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="nf">localize</span><span class="p">(</span><span class="nf">title</span><span class="p">(</span><span class="nv">for</span><span class="p">:),</span> <span class="nf">setTitle</span><span class="p">(</span><span class="nv">_</span><span class="p">:</span><span class="nv">for</span><span class="p">:))</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice that for <code class="language-plaintext highlighter-rouge">UIButton</code> title we use another helper function which applies localization for all
possible control states.</p>
<p>Views are not the only objects we can configure with the Interface Builder. We should keep in mind
the following objects too:</p>
<ul>
<li>
<p><code class="language-plaintext highlighter-rouge">UIBarItem</code> with it’s subclasses: <code class="language-plaintext highlighter-rouge">UIBarButtonItem</code> and <code class="language-plaintext highlighter-rouge">UITabBarItem</code></p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">UINavigationItem</code></p>
</li>
</ul>
<p>Any other objects you decide to use in your app</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UIBarItem</span><span class="p">:</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">localize</span><span class="p">(</span><span class="n">title</span><span class="p">)</span> <span class="p">{</span> <span class="n">title</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UIBarButtonItem</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">override</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="n">customView</span><span class="p">?</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">extension</span> <span class="kt">UINavigationItem</span><span class="p">:</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">localize</span><span class="p">(</span><span class="n">title</span><span class="p">)</span> <span class="p">{</span> <span class="n">title</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}</span>
<span class="nf">localize</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span> <span class="p">{</span> <span class="n">prompt</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}</span>
<span class="n">titleView</span><span class="p">?</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="n">leftBarButtonItems</span><span class="p">?</span><span class="o">.</span><span class="n">forEach</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span> <span class="p">}</span>
<span class="n">rightBarButtonItems</span><span class="p">?</span><span class="o">.</span><span class="n">forEach</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Finally, we have to start the flow somewhere. I usually rely on the following events:</p>
<ul>
<li>
<p>Localize <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">navigationItem</code>, <code class="language-plaintext highlighter-rouge">tabBarItem</code> and <code class="language-plaintext highlighter-rouge">view</code> in the <code class="language-plaintext highlighter-rouge">viewDidLoad</code> method of
my <code class="language-plaintext highlighter-rouge">UIViewController</code> subclasses.</p>
</li>
<li>
<p>Localize contents of <code class="language-plaintext highlighter-rouge">UITableViewCell</code> and <code class="language-plaintext highlighter-rouge">UICollectionViewCell</code> subclasses in the
corresponding <code class="language-plaintext highlighter-rouge">awakeFromNib</code> methods.</p>
</li>
</ul>
<p>For the <code class="language-plaintext highlighter-rouge">UIViewController</code> here is a helper method to localize content, navigation and tab items:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UIViewController</span><span class="p">:</span> <span class="kt">Localizable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">localize</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">localize</span><span class="p">(</span><span class="n">title</span><span class="p">)</span> <span class="p">{</span> <span class="n">title</span> <span class="o">=</span> <span class="nv">$0</span> <span class="p">}</span>
<span class="n">navigationItem</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="n">tabBarItem</span><span class="p">?</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="n">view</span><span class="o">.</span><span class="nf">localize</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
Generic Optional Handling in Swift2017-08-13T00:00:00+00:00https://unpredictable.tech/2017/08/13/generic-optional-handling-in-swift/<p>Sometimes you want to write a generic algorithm working on any <code class="language-plaintext highlighter-rouge">Optional</code> type no matter what actual type
is wrapped inside. Ok, this can be easily done with a free generic function, but what if you want to write
a <code class="language-plaintext highlighter-rouge">Sequence</code> extension to remove all <code class="language-plaintext highlighter-rouge">nil</code> values for example?</p>
<p>Things get a little bit complicated here since <code class="language-plaintext highlighter-rouge">Optional</code> is not a protocol but a concrete type and so it
can’t be used as a generic type constraint.</p>
<!-- more -->
<p>Generic protocols and concrete types in Swift serve different purposes: we create instances and declare
variables of concrete types while protocols can be used as a generic type constraints.</p>
<p>Type erasure is a technique used in case we want to declare a variable able to hold any concrete type
conforming to a specific protocol. What we want here instead is another part of the same puzzle, we need
a protocol allowing us to use the concrete generic type as a constraint.</p>
<p>This may sound complicated in English but, as it usually happens, looks much simpler when
written in plain Swift 😄</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">OptionalType</span><span class="p">:</span> <span class="kt">ExpressibleByNilLiteral</span> <span class="p">{</span>
<span class="kd">associatedtype</span> <span class="kt">WrappedType</span>
<span class="k">var</span> <span class="nv">asOptional</span><span class="p">:</span> <span class="kt">WrappedType</span><span class="p">?</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">extension</span> <span class="kt">Optional</span><span class="p">:</span> <span class="kt">OptionalType</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">asOptional</span><span class="p">:</span> <span class="kt">Wrapped</span><span class="p">?</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">self</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So here we just define an <code class="language-plaintext highlighter-rouge">OptionalType</code> protocol declaring <code class="language-plaintext highlighter-rouge">WrappedType</code> associated type and conform <code class="language-plaintext highlighter-rouge">Optional</code>
enum to it. Note that generic type parameters do not automatically fulfill protocol requirements, but we
have type inference covering us here.</p>
<p>In order to make the protocol useful we expose some basic <code class="language-plaintext highlighter-rouge">Optional</code> functionality:</p>
<ul>
<li>
<p><code class="language-plaintext highlighter-rouge">asOptional</code> property gives us an access to the optional binding syntax.</p>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">ExpressibleByNilLiteral</code> conformance allows us to use nil for initialization.</p>
</li>
</ul>
<p>Having done that, we can now use <code class="language-plaintext highlighter-rouge">OptionalType</code> as a generic constraint:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">extension</span> <span class="kt">Sequence</span> <span class="k">where</span> <span class="k">Self</span><span class="o">.</span><span class="kt">Iterator</span><span class="o">.</span><span class="kt">Element</span><span class="p">:</span> <span class="kt">OptionalType</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">removingNils</span><span class="p">()</span> <span class="o">-></span> <span class="p">[</span><span class="k">Self</span><span class="o">.</span><span class="kt">Iterator</span><span class="o">.</span><span class="kt">Element</span><span class="o">.</span><span class="kt">WrappedType</span><span class="p">]</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">flatMap</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="n">asOptional</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If you are looking for more tricks that can be done with the <code class="language-plaintext highlighter-rouge">Optional</code> enum,
you should check <a href="http://www.russbishop.net/improving-optionals">an excellent article by Russ Bishop</a>.</p>
Using Self in Swift Class Extensions2017-08-10T00:00:00+00:00https://unpredictable.tech/2017/08/10/using-self-in-swift-class-extensions/<p>It might be tempting to use <code class="language-plaintext highlighter-rouge">Self</code> as a parameter type when extending classes but Swift only allows it
in a protocol or as the result of a class method invocation.</p>
<p>In fact, this is a semantically correct restriction for non-final classes in most cases, except when we
want to use <code class="language-plaintext highlighter-rouge">Self</code> as an argument of the closure, think about completion handlers for example. In that case
<code class="language-plaintext highlighter-rouge">Self</code> is used just as an another method call result which is absolutely valid option.</p>
<!-- more -->
<p>My favorite example here is the continuation helper for the Operation class:</p>
<ul>
<li>
<p>Using continuation operation instead of completion block gives control over its execution context.</p>
</li>
<li>
<p>I tend to define result accessors in my Operation subclasses and I usually want to access them in
a continuation.</p>
</li>
<li>
<p>Accessing operation from the continuation does not introduce a retain cycle because any operation already
owns its dependencies.</p>
</li>
</ul>
<p>So we need to pass a block receiving operation that has just finished execution as a parameter. That is not
allowed in a class extension.</p>
<p>Hm, but we can use Self that way in a protocol, right… Protocols to the rescue! The plan is to define a
dummy protocol, conform our class to it and extend the protocol instead of the class.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">BlockContinuable</span> <span class="p">{</span> <span class="p">}</span>
<span class="kd">extension</span> <span class="kt">Operation</span><span class="p">:</span> <span class="kt">BlockContinuable</span> <span class="p">{</span> <span class="p">}</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">BlockContinuable</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="kt">Operation</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="p">`</span><span class="nv">continue</span><span class="p">`(</span><span class="n">on</span> <span class="nv">queue</span><span class="p">:</span> <span class="kt">OperationQueue</span> <span class="o">=</span> <span class="o">.</span><span class="n">main</span><span class="p">,</span> <span class="n">with</span> <span class="nv">block</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">(</span><span class="k">Self</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">continuation</span> <span class="o">=</span> <span class="kt">BlockOperation</span> <span class="p">{</span> <span class="nf">block</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="p">}</span>
<span class="n">continuation</span><span class="o">.</span><span class="nf">addDependency</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
<span class="n">queue</span><span class="o">.</span><span class="nf">addOperation</span><span class="p">(</span><span class="n">continuation</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now we can use our <code class="language-plaintext highlighter-rouge">continue(on:with:)</code> extension and access operation result in a type-safe manner:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="kt">SampleOperation</span><span class="p">:</span> <span class="kt">Operation</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">result</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span>
<span class="kd">public</span> <span class="k">override</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="s">"Hello, Continuation!"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">operation</span> <span class="o">=</span> <span class="kt">SampleOperation</span><span class="p">()</span>
<span class="n">operation</span><span class="o">.</span><span class="k">continue</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="nv">$0</span><span class="o">.</span><span class="n">result</span> <span class="p">??</span> <span class="s">"operation failed"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kt">OperationQueue</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="nf">addOperation</span><span class="p">(</span><span class="n">operation</span><span class="p">)</span>
</code></pre></div></div>
Managing Temporary Files in Swift2017-08-08T00:00:00+00:00https://unpredictable.tech/2017/08/08/managing-temporary-files-in-swift/<p>Reference counting is great in taking unused objects out of memory. The same can be applied to the temporary files we allocate.</p>
<!-- more -->
<p>Let’s say you are building a video sharing app, here is what you have to do each time user decides to upload some content
from the app:</p>
<ul>
<li>
<p>Take a movie and store into a temporary file.</p>
</li>
<li>
<p>Present filter/crop/whatever editing UI to the user.</p>
</li>
<li>
<p>Render the final video to another temporary file, the first file can be safely removed by now.</p>
</li>
<li>
<p>Upload video to the cloud and remove the second file when done.</p>
</li>
</ul>
<p>Taking care of those files manually adds extra complexity and can be easily overseen resulting in an excessive storage
use caused by the lost data. I faced this myself when my pet project suddenly took over all my storage 😂</p>
<p>Reference counting comes to the rescue here: we can create <code class="language-plaintext highlighter-rouge">TemporaryFileURL</code> class wrapping regular <code class="language-plaintext highlighter-rouge">URL</code> and performing
cleanup in its deinit method. Now the temporary file will be removed automatically when it becomes unreferenced from
the application.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">TemporaryFileURL</span><span class="p">:</span> <span class="kt">ManagedURL</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">let</span> <span class="nv">contentURL</span><span class="p">:</span> <span class="kt">URL</span>
<span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="kd">extension</span> <span class="nv">ext</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
<span class="n">contentURL</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">fileURLWithPath</span><span class="p">:</span> <span class="kt">NSTemporaryDirectory</span><span class="p">())</span>
<span class="o">.</span><span class="nf">appendingPathComponent</span><span class="p">(</span><span class="kt">UUID</span><span class="p">()</span><span class="o">.</span><span class="n">uuidString</span><span class="p">)</span>
<span class="o">.</span><span class="nf">appendingPathExtension</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">deinit</span> <span class="p">{</span>
<span class="kt">DispatchQueue</span><span class="o">.</span><span class="nf">global</span><span class="p">(</span><span class="nv">qos</span><span class="p">:</span> <span class="o">.</span><span class="n">utility</span><span class="p">)</span><span class="o">.</span><span class="n">async</span> <span class="p">{</span> <span class="p">[</span><span class="n">contentURL</span> <span class="o">=</span> <span class="k">self</span><span class="o">.</span><span class="n">contentURL</span><span class="p">]</span> <span class="k">in</span>
<span class="k">try</span><span class="p">?</span> <span class="kt">FileManager</span><span class="o">.</span><span class="k">default</span><span class="o">.</span><span class="nf">removeItem</span><span class="p">(</span><span class="nv">at</span><span class="p">:</span> <span class="n">contentURL</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice the rarely used capture with assignment syntax I used here to pass <code class="language-plaintext highlighter-rouge">contentURL</code> for the deferred file
cleanup: we’d better not capture <code class="language-plaintext highlighter-rouge">self</code> during deallocation so we just copy the underlying file URL and let
<code class="language-plaintext highlighter-rouge">self</code> deallocate properly.</p>
<p>Now you may want to unify all the code working with files no matter if they are normal or temporary. That’s
what <code class="language-plaintext highlighter-rouge">ManagedURL</code> protocol stands here for. We can conform <code class="language-plaintext highlighter-rouge">URL</code> struct and/or <code class="language-plaintext highlighter-rouge">NSURL</code> class to the protocol and pass
<code class="language-plaintext highlighter-rouge">ManagedURL</code> references all around.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">ManagedURL</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">contentURL</span><span class="p">:</span> <span class="kt">URL</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">keepAlive</span><span class="p">()</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">ManagedURL</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">keepAlive</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">extension</span> <span class="kt">URL</span><span class="p">:</span> <span class="kt">ManagedURL</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">contentURL</span><span class="p">:</span> <span class="kt">URL</span> <span class="p">{</span> <span class="k">return</span> <span class="k">self</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I have also added a no-op <code class="language-plaintext highlighter-rouge">keepAlive</code> function whose sole purpose it to allow easy object capture by various closures
used as a completion handlers. This allows us to keep file while background operation is executed like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">URLSession</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="nf">uploadTask</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">request</span><span class="p">,</span> <span class="nv">fromFile</span><span class="p">:</span> <span class="n">fileToUpload</span><span class="o">.</span><span class="n">contentURL</span><span class="p">)</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="k">in</span>
<span class="n">temporaryFile</span><span class="o">.</span><span class="nf">keepAlive</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>As <a href="https://twitter.com/ketzusaka">James Richard</a> reminded on Twitter, this technique is called
<a href="https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization">Resource Acquisition is Initialization</a>,
or RAII, and has beed commonly used in C++ for ages. The trick is good for managing lifetime of any external
resource but is often overlooked since destructors are not very common in the modern world of ARC, GC, defer,
try/finally and others.</p>
Storyboard Tricks2017-08-06T00:00:00+00:00https://unpredictable.tech/2017/08/06/storyboard-tricks/<p>While looking through another sample project today, I have once again noticed how many string literals and force downcasts accompany most of the storyboard-related code.</p>
<p>Having realized that, I decided to share a few practices I use myself to make my view controller and storyboard handling code more conscious.</p>
<!-- more -->
<h2 id="instantiating-view-controllers">Instantiating View Controllers</h2>
<p>Let’s start with the instantiation process: we rely on file name to create <code class="language-plaintext highlighter-rouge">UIStoryboard</code>
instance, then we use view controller identifier to call <code class="language-plaintext highlighter-rouge">instantiateViewController(withIdentifier:)</code>
and all this mess is followed by the force downcast to the actual type.</p>
<p>View controller instantiation code should be much cleaner, here is an example of what I’m looking for:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">func</span> <span class="nf">presentDetails</span><span class="p">(</span><span class="k">for</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">ItemModel</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">viewController</span> <span class="o">=</span> <span class="kt">DetailsViewController</span><span class="o">.</span><span class="nf">makeWithStoryboard</span><span class="p">()</span>
<span class="n">viewController</span><span class="o">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="k">self</span>
<span class="n">viewController</span><span class="o">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">item</span>
<span class="nf">present</span><span class="p">(</span><span class="n">viewController</span><span class="p">,</span> <span class="nv">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nv">completion</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To achieve that we have to avoid “massive storyboard” pattern and keep each flow in a separate file.
Having done that we can establish simple conventions allowing us to hide all that UIStoryboard stuff
in a helper function:</p>
<ul>
<li>
<p>Only instantiate initial view controllers from code.</p>
</li>
<li>
<p>Access all other view controllers in the same storyboard via segues.</p>
</li>
<li>
<p>Use initial view controller class name to name the corresponding storyboard.
This is obvious for good old NIBs but we tend to not use the pattern with storyboards.</p>
</li>
</ul>
<p>After establishing the conventions we can easily instantiate any view controller given only its class,
everything else is derived programmatically. Helper function code should be something similar to the
following snippet:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">private</span> <span class="kd">func</span> <span class="n">dynamicCast</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">object</span><span class="p">:</span> <span class="kt">Any</span><span class="p">,</span> <span class="nv">as</span><span class="p">:</span> <span class="kt">T</span><span class="o">.</span><span class="k">Type</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span><span class="p">?</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">object</span> <span class="k">as?</span> <span class="kt">T</span>
<span class="p">}</span>
<span class="kd">public</span> <span class="kd">extension</span> <span class="kt">UIViewController</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">func</span> <span class="nf">makeWithStoryboard</span><span class="p">(</span><span class="n">_</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span><span class="p">,</span> <span class="nv">bundle</span><span class="p">:</span> <span class="kt">Bundle</span><span class="p">?</span> <span class="o">=</span> <span class="kc">nil</span><span class="p">)</span> <span class="o">-></span> <span class="k">Self</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">name</span> <span class="o">=</span> <span class="n">name</span> <span class="p">??</span> <span class="kt">String</span><span class="p">(</span><span class="nv">describing</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span><span class="o">.</span><span class="nf">components</span><span class="p">(</span><span class="nv">separatedBy</span><span class="p">:</span> <span class="s">"."</span><span class="p">)</span><span class="o">.</span><span class="n">last</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">bundle</span> <span class="o">=</span> <span class="n">bundle</span> <span class="p">??</span> <span class="kt">Bundle</span><span class="p">(</span><span class="nv">for</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="k">guard</span> <span class="n">bundle</span><span class="o">.</span><span class="nf">url</span><span class="p">(</span><span class="nv">forResource</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="nv">withExtension</span><span class="p">:</span> <span class="s">"storyboardc"</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Can't find storyboard named `</span><span class="se">\(</span><span class="n">name</span><span class="se">)</span><span class="s">` in bundle `</span><span class="se">\(</span><span class="n">bundle</span><span class="se">)</span><span class="s">`."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">storyboard</span> <span class="o">=</span> <span class="kt">UIStoryboard</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="nv">bundle</span><span class="p">:</span> <span class="n">bundle</span><span class="p">)</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">initialViewController</span> <span class="o">=</span> <span class="n">storyboard</span><span class="o">.</span><span class="nf">instantiateInitialViewController</span><span class="p">()</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"No initial view controller defined in storyboard `</span><span class="se">\(</span><span class="n">name</span><span class="se">)</span><span class="s">`, bundle `</span><span class="se">\(</span><span class="n">bundle</span><span class="se">)</span><span class="s">`."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">resultViewController</span> <span class="o">=</span> <span class="nf">dynamicCast</span><span class="p">(</span><span class="n">initialViewController</span><span class="p">,</span> <span class="nv">as</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Wrong initial view controller found in storyboard `</span><span class="se">\(</span><span class="n">name</span><span class="se">)</span><span class="s">`, bundle `</span><span class="se">\(</span><span class="n">bundle</span><span class="se">)</span><span class="s">`: expected `</span><span class="se">\(</span><span class="k">self</span><span class="se">)</span><span class="s">`, found `</span><span class="se">\(</span><span class="nf">type</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">initialViewController</span><span class="p">)</span><span class="se">)</span><span class="s">`."</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">resultViewController</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I’d like to note two tricky moments here:</p>
<ul>
<li>
<p>We use <code class="language-plaintext highlighter-rouge">Bundle(for: self)</code> instead of <code class="language-plaintext highlighter-rouge">nil</code> or <code class="language-plaintext highlighter-rouge">Bundle.main</code> to properly load resources from dynamic frameworks.</p>
</li>
<li>
<p>That weird <code class="language-plaintext highlighter-rouge">dynamicCast(_:as:)</code> function helps us to work around Swift limitation which prohibits us to
write <code class="language-plaintext highlighter-rouge">initialViewController as? Self</code>. Doing the former results in a compile error stating that “<code class="language-plaintext highlighter-rouge">Self</code> is
only available in a protocol or as the result of a method in a class”.</p>
</li>
</ul>
<h2 id="handling-segues">Handling Segues</h2>
<p>Another popular place to find string identifiers when working with storyboards is <code class="language-plaintext highlighter-rouge">prepare(for:sender:)</code> method.
Here we test segue identifier and downcast view controller depending on that. Something like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">override</span> <span class="kd">func</span> <span class="nf">prepare</span><span class="p">(</span><span class="k">for</span> <span class="nv">segue</span><span class="p">:</span> <span class="kt">UIStoryboardSegue</span><span class="p">,</span> <span class="nv">sender</span><span class="p">:</span> <span class="kt">Any</span><span class="p">?)</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">segue</span><span class="o">.</span><span class="n">identifier</span> <span class="o">==</span> <span class="s">"OpenAnotherViewController"</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">destination</span> <span class="o">=</span> <span class="n">segue</span><span class="o">.</span><span class="n">destination</span> <span class="k">as!</span> <span class="kt">AnotherViewController</span>
<span class="n">destination</span><span class="o">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="k">self</span>
<span class="k">return</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The snippet employs two bad practices at once: error-prone string identifier comparison followed by force downcast.</p>
<p>It seems to me that the only thing that actually matters in most cases is our destination view controller type.
In those cases we can simply switch over the possible destinations and <code class="language-plaintext highlighter-rouge">fatalError</code> for everything else. The following
code snippet shows how this may look in your code:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">override</span> <span class="kd">func</span> <span class="nf">prepare</span><span class="p">(</span><span class="k">for</span> <span class="nv">segue</span><span class="p">:</span> <span class="kt">UIStoryboardSegue</span><span class="p">,</span> <span class="nv">sender</span><span class="p">:</span> <span class="kt">Any</span><span class="p">?)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">segue</span><span class="o">.</span><span class="n">destination</span> <span class="p">{</span>
<span class="k">case</span> <span class="k">let</span> <span class="nv">destination</span> <span class="k">as</span> <span class="kt">AnotherViewController</span><span class="p">:</span>
<span class="n">destination</span><span class="o">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="k">self</span>
<span class="k">default</span><span class="p">:</span>
<span class="nf">fatalError</span><span class="p">(</span><span class="s">"Unexpected segue: `</span><span class="se">\(</span><span class="k">self</span><span class="se">)</span><span class="s">` -> `</span><span class="se">\(</span><span class="n">segue</span><span class="o">.</span><span class="n">destination</span><span class="se">)</span><span class="s">`"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>