
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.lordcodes.com/">
  <title>Lord Codes » iOS &amp; Swift Feed</title>
  <subtitle>Lord Codes blog content on iOS, Swift and other content aimed at iOS developers. Learn about the basics and advanced topics to help you build better apps.</subtitle>
  <link href="https://www.lordcodes.com/ios/atom.xml" rel="self"/>
  <link href="https://www.lordcodes.com/ios/"/>
  <updated>2023-12-21T00:00:00Z</updated>
  <id>https://www.lordcodes.com/ios/</id>
  <author>
    <name>Andrew Lord</name>
    <uri>https://www.lordcodes.com/about/</uri>
  </author>  <entry>
    <title>Installing and running Swift tools with enforced versions</title>
    <link href="https://www.lordcodes.com/articles/swift-tools-enforced-versions/"/>
    <updated>2023-12-21T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/swift-tools-enforced-versions/</id>
    <content type="html">
      &lt;p&gt;Working on Swift projects often involves using tools to help with tasks such as linting using &lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;SwiftLint&lt;/a&gt; or generating code using &lt;a href=&quot;https://github.com/krzysztofzablocki/Sourcery&quot;&gt;Sourcery&lt;/a&gt;. When running tools we want to ensure all developers of the project are using the same version and that a specific version can be chosen to ensure compatibility. For most Swift tools there is the choice of many different installation methods, each with its own benefits and drawbacks, so for many people it might not be obvious what the best option is.&lt;/p&gt;&lt;p&gt;Before we look at the installation methods, let&#39;s consider what we would like to be able to do:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Enforce versions between team members&lt;/li&gt;&lt;li&gt;Use a specific version for each project&lt;/li&gt;&lt;li&gt;Use the same version locally and on CI&lt;/li&gt;&lt;li&gt;Install tools quickly&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;installation-options&quot; tabindex=&quot;-1&quot;&gt;Installation options&lt;/h2&gt;&lt;h3 id=&quot;homebrew&quot; tabindex=&quot;-1&quot;&gt;Homebrew&lt;/h3&gt;&lt;p&gt;Homebrew is a popular package manager for Mac and is useful for installing tools and apps, even allowing use of a &lt;code&gt;Brewfile&lt;/code&gt;. Unfortunately, unless a particular version is provided as a formula we cannot install a specific version, instead we would need to require team members to update to the latest version. On top of this some tools may not be published to Homebrew and releases can take longer to arrive.&lt;/p&gt;&lt;h3 id=&quot;swift-package-manager-plugins&quot; tabindex=&quot;-1&quot;&gt;Swift Package Manager Plugins&lt;/h3&gt;&lt;p&gt;SPM has support for command and build-time plugins, linking to specific versions. Unfortunately, adding them to Xcode projects only allows running command plugins via the UI, so we would need an SPM package with a &lt;code&gt;Package.swift&lt;/code&gt; to run them from the command-line. Depending on the tool we are running we may need to build our own plugin.&lt;/p&gt;&lt;h3 id=&quot;cocoapods&quot; tabindex=&quot;-1&quot;&gt;Cocoapods&lt;/h3&gt;&lt;p&gt;Many tools offer installation via &lt;a href=&quot;https://cocoapods.org&quot;&gt;Cocoapods&lt;/a&gt; and running them from the &lt;code&gt;Pods&lt;/code&gt; directory. Although we can pin to a specific version, not all tools will be available via Cocoapods. The main issue is that it requires the project to already be using Cocoapods or to add Cocoapods to it, which is Ruby-based.&lt;/p&gt;&lt;h3 id=&quot;mint&quot; tabindex=&quot;-1&quot;&gt;Mint&lt;/h3&gt;&lt;p&gt;Swift tools can be built and installed using &lt;a href=&quot;https://github.com/yonaskolb/mint&quot;&gt;Mint&lt;/a&gt;, where we can enforce versions using a &lt;code&gt;Mintfile&lt;/code&gt;. We will of course need another method for installing Mint at the right version itself. Many people use Mint happily, however it can be very slow building tools from sources when the version changes, particular on CI where we will need caching to avoid this happening for every build.&lt;/p&gt;&lt;h3 id=&quot;binary-or-cloning&quot; tabindex=&quot;-1&quot;&gt;Binary or cloning&lt;/h3&gt;&lt;p&gt;Instead of using a package manager, we could download the tool as a binary from the GitHub release or clone the repository and build it for ourselves. It will be difficult to ensure developers keep tools up-to-date and so the approach will likely involve maintaining some scripts.&lt;/p&gt;&lt;h2 id=&quot;an-alternative-approach&quot; tabindex=&quot;-1&quot;&gt;An alternative approach&lt;/h2&gt;&lt;p&gt;For many teams one of these installation methods may be the right approach, however they do come with some potential drawbacks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;It may not be easy to use or error-prone&lt;/li&gt;&lt;li&gt;Specifying and enforcing the version may not be possible&lt;/li&gt;&lt;li&gt;Installation may involve building the tool from sources with its dependencies&lt;/li&gt;&lt;li&gt;One of the tools may not support a particular installation method&lt;/li&gt;&lt;li&gt;Our project may not be using Cocoapods or SPM&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For a while I have been successfully using binaries wrapped with scripts to manage download, installation and execution. For developers it is much quicker than any method that builds from sources, it ensures consistent versions and it isn&#39;t dependent on use of any external package managers.&lt;/p&gt;&lt;h3 id=&quot;the-scripts&quot; tabindex=&quot;-1&quot;&gt;The scripts&lt;/h3&gt;&lt;p&gt;First, we need to create a folder in the project to store the tools and then a script for the tool in question, such as &lt;code&gt;swiftlint.sh&lt;/code&gt;. We start the script by specifying the version at the top where it is easy to update.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VERSION&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0.54.0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We need to calculate the installation directory based on the script location. Make sure to add &lt;code&gt;BuildTools/Tools&lt;/code&gt; to the &lt;code&gt;gitignore&lt;/code&gt; to avoid binaries or sources being added to source control.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BASEDIR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dirname&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$0&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;INSTALL_DIR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${BASEDIR}&lt;/span&gt;/Tools/SwiftLint&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;EXECUTABLE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${INSTALL_DIR}&lt;/span&gt;/swiftlint&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SwiftLint is provided as a binary on the GitHub release so we can download the version we need.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;DOWNLOAD_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/realm/SwiftLint/releases/download&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;DOWNLOAD_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/&lt;span class=&quot;token variable&quot;&gt;$VERSION&lt;/span&gt;/portable_swiftlint.zip&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can now write our install function which will download and unzip the binary, before marking it as safe to execute on Mac.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;install_tool&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$INSTALL_DIR&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-LO&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$DOWNLOAD_URL&lt;/span&gt; --output-dir &lt;span class=&quot;token variable&quot;&gt;$BASEDIR&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;unzip&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BASEDIR&lt;/span&gt;/portable_swiftlint.zip &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$INSTALL_DIR&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BASEDIR&lt;/span&gt;/portable_swiftlint.zip
    xattr &lt;span class=&quot;token parameter variable&quot;&gt;-dr&lt;/span&gt; com.apple.quarantine &lt;span class=&quot;token variable&quot;&gt;$EXECUTABLE&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the executable is not already installed, we use our function to install it.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$EXECUTABLE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$EXECUTABLE&lt;/span&gt; not found, installing…&quot;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$INSTALL_DIR&lt;/span&gt;
    install_tool
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the executable is already installed, we check if it is the right version and re-install it if not.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;INSTALLED_VERSION&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;./$EXECUTABLE &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$VERSION&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$INSTALLED_VERSION&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Version out-of-date, re-installing…&quot;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$INSTALL_DIR&lt;/span&gt;
    install_tool
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, we run the executable, passing any arguments to it.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;./&lt;span class=&quot;token variable&quot;&gt;$EXECUTABLE&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${@&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;1}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An installable version of the full script is available &lt;a href=&quot;https://github.com/lordcodes/swiftlint-cli&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;h3 id=&quot;supported-tools&quot; tabindex=&quot;-1&quot;&gt;Supported tools&lt;/h3&gt;&lt;p&gt;Whenever a binary can be linked to for a particular version by URL, such as GitHub releases, it will be compatible with this approach. If no binary is available the script could be adapted to obtain it via cloning and building from the Git tag as a backup.&lt;/p&gt;&lt;p&gt;I have been using this approach to run:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;SwiftLint, &lt;a href=&quot;https://github.com/lordcodes/swiftlint-cli&quot;&gt;installable version on GitHub&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;SwiftFormat, &lt;a href=&quot;https://github.com/lordcodes/swiftformat-cli&quot;&gt;installable version on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Sourcery&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The installable versions also include details of using them witin Fastlane, which is great for projects that are using Fastlane for automation.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Using scripts to install and run our tools combines the best of the options, whils keeping performance high:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Easy to use&lt;/li&gt;&lt;li&gt;Enforces versions of our tools across the team&lt;/li&gt;&lt;li&gt;Independent versions for different projects&lt;/li&gt;&lt;li&gt;Quicker than approaches that checkout and build from source&lt;/li&gt;&lt;li&gt;Supports local and CI&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It would be unfair if we didn&#39;t also consider the drawbacks, in that we have to maintain a script for each tool and the approach only works best when there is a binary available for download.&lt;/p&gt;&lt;p&gt;Hopefully eventually SPM command plugins will be executable from the command-line for Xcode projects in a performant way. This would make that the preferred approach due to being built-in and not involving maintaining custom scripts to run.&lt;/p&gt;
    </content>
  </entry>  <entry>
    <title>Manage automation tasks using Swift Package Manager</title>
    <link href="https://www.lordcodes.com/articles/manage-automation-tasks-using-spm/"/>
    <updated>2020-03-08T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/manage-automation-tasks-using-spm/</id>
    <content type="html">
      &lt;p&gt;Now that we have Swift Package Manager for including framework dependencies, wouldn&#39;t it be great if we could use it to install and run our command line tool dependencies as well? What if I told you that this was already possible, allowing you to add tools like &lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;SwiftLint&lt;/a&gt; to your project within &lt;code&gt;Package.swift&lt;/code&gt; and run automation tasks easily and with minimal configuration.&lt;/p&gt;&lt;p&gt;When working on software projects there are usually a set of different scripts for running project automation, or maybe a selection of different command line tools all the developers install on their system. For a Swift project many of these tools are written in Swift, yet we still end up installing them with other package managers such as &lt;a href=&quot;https://github.com/Homebrew/brew&quot;&gt;Homebrew&lt;/a&gt; or &lt;a href=&quot;https://github.com/yonaskolb/Mint&quot;&gt;Mint&lt;/a&gt;. These package managers are fantastic and perfect for installing our tools, however when we already have Swift Package Manager (SPM) it would be great if we could use that directly.&lt;/p&gt;&lt;p&gt;We will explore setting up all of our command line tool dependencies using Swift Package Manager, discuss how to run them and then move onto how to write automation tasks using a small CLI within our project.&lt;/p&gt;&lt;h2 id=&quot;installing-and-running&quot; tabindex=&quot;-1&quot;&gt;Installing and running&lt;/h2&gt;&lt;p&gt;Swift command line tools can be added to our project by simply adding them as a dependency within &lt;code&gt;Package.swift&lt;/code&gt;, alongside framework dependencies we may already be using. We will be running the tools directly and so there is no need to add them as dependencies to any of our targets, we just need SPM to download them for us.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; package &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uploader&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    products&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;executable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;uploader-cli&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; targets&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uploader&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    dependencies&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/realm/SwiftLint&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            from&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0.39.1&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/nicklockwood/SwiftFormat&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            from&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0.44.4&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/apple/swift-argument-parser&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            from&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    targets&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uploader&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            dependencies&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uploader&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ArgumentParser&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For our Uploader &lt;code&gt;Package.swift&lt;/code&gt; alongside ArgumentParser which we are using as a dependency on our main target, we can include tools: &lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;SwiftLint&lt;/a&gt; and &lt;a href=&quot;https://github.com/nicklockwood/SwiftFormat&quot;&gt;SwiftFormat&lt;/a&gt;. As they are added just like other dependencies, we can specify the version of the command line tool to use, allowing all developers on the project to use the same version. This is especially important for tools that are linting or formatting code, as it means the same rules will be applied for all developers.&lt;/p&gt;&lt;p&gt;Running our tools is now as simple as using &lt;code&gt;swift run&lt;/code&gt;, simple! The same process can be used locally and on CI, which means we get the same versions of the tools in both places!&lt;/p&gt;&lt;pre&gt;&lt;code&gt;swift run swiftlint
swift run swiftformat .
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;managing-automation-tasks&quot; tabindex=&quot;-1&quot;&gt;Managing automation tasks&lt;/h2&gt;&lt;p&gt;On top of running command line tools as we have done so far, it would be great if we could also run all of our project automation in the same way. We could of course simply use Swift scripts, however, if any of them need dependencies this would need to be managed and having a bunch of different scripts may not be as discoverable as it could be.&lt;/p&gt;&lt;p&gt;An alternative is that we create a small CLI within &lt;code&gt;Package.swift&lt;/code&gt; that provides a set of automation tasks via subcommands that can then be called in a similar way to the lanes in &lt;a href=&quot;https://github.com/fastlane/fastlane&quot;&gt;Fastlane&lt;/a&gt; for those who are familiar with it.&lt;/p&gt;&lt;p&gt;The first step to creating our CLI is adding a target that will contain the code for our automation tasks.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;targets&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UploaderTasks&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        dependencies&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ArgumentParser&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ShellOut&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next step is adding an executable product that uses the new target. Make sure to use a simple name for the executable so that it is easy to run, a personal preference being &lt;code&gt;task&lt;/code&gt;. Our automation tasks will now be ran using &lt;code&gt;swift run task TASK_NAME&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;products&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;executable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;task&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; targets&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UploaderTasks&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-main-command&quot; tabindex=&quot;-1&quot;&gt;The main command&lt;/h2&gt;&lt;p&gt;Our task executable is developed just like any other CLI, although it will be a simple one containing very little code. We could do it manually within &lt;code&gt;main.swift&lt;/code&gt;, however, as we will need to run different tasks as arguments to the main command we will need to be parsing these arguments and making it easy for users to find the tasks they can run. To make this really easy there is the &lt;a href=&quot;https://github.com/apple/swift-argument-parser&quot;&gt;ArgumentParser&lt;/a&gt; framework from Apple.&lt;/p&gt;&lt;p&gt;Within the &lt;code&gt;main.swift&lt;/code&gt; file we create a struct for our main command. This configures the command name, offers text for the help message and provides our tasks as subcommands. We will be providing &lt;code&gt;lint&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt; and &lt;code&gt;uninstall&lt;/code&gt;. To execute our program we call &lt;code&gt;Tasks.main()&lt;/code&gt; at the bottom of the &lt;code&gt;main.swift&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ParsableCommand&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        commandName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tasks&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        abstract&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;An automation task runner for Uploader.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        subcommands&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Linting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uninstall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Tasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before creating our first subcommand, we need to make sure it is easy for our subcommands to execute shell commands such as running other CLI tools or scripts. For doing this there is a great framework called &lt;a href=&quot;https://github.com/JohnSundell/ShellOut&quot;&gt;ShellOut&lt;/a&gt;. Rather than calling it directly we can write a small wrapper function that handles errors, streams output as output from our CLI and allows execution to continue after an error.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; continueOnError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shellOut&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            to&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            outputHandle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;standardOutput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            errorHandle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;standardError
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;continueOnError &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShellError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShellError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomStringConvertible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed when running shell command&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the &lt;code&gt;outputHandle&lt;/code&gt; and &lt;code&gt;errorHandle&lt;/code&gt; weren&#39;t connected to standard output and standard error, we would need to print the output of the &lt;code&gt;shellOut&lt;/code&gt; call. By using these handles it will appear in the terminal we are running our task from as it is produced. This means we don&#39;t need the output from &lt;code&gt;shellOut&lt;/code&gt; or the error it throws as the information has already been shown to the user by the point it is received.&lt;/p&gt;&lt;h2 id=&quot;lint&quot; tabindex=&quot;-1&quot;&gt;Lint&lt;/h2&gt;&lt;p&gt;For each task we want to add, we create a subcommand to our main &lt;code&gt;Tasks&lt;/code&gt; command. We already registered these above and will now work through creating each of the subcommands, starting with the lint task. We are running &lt;code&gt;SwiftFormat&lt;/code&gt; in lint mode and then &lt;code&gt;SwiftLint&lt;/code&gt;, allowing execution to continue on error so that we get all of the failures out of both tools.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tasks&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Linting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ParsableCommand&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            commandName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lint&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            abstract&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Lint the Uploader codebase, such as static analysis.&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;swift run swiftformat . --lint&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; continueOnError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;swift run swiftlint&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This task is ran using &lt;code&gt;swift run task lint&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;We can create another subcommand to format code using &lt;code&gt;SwiftLint&lt;/code&gt; auto-correct and &lt;code&gt;SwiftFormat&lt;/code&gt; in its regular mode, feel free to add this to your project in the same way as writing our &lt;code&gt;Linting&lt;/code&gt; struct.&lt;/p&gt;&lt;h2 id=&quot;install-and-uninstall&quot; tabindex=&quot;-1&quot;&gt;Install and uninstall&lt;/h2&gt;&lt;p&gt;If our Swift project is itself a CLI, our users will need to install and uninstall it, both tasks either being provided by a script or a Makefile. We can offer these tasks via subcommands in our task runner.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tasks&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ParsableCommand&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            commandName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;install&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            abstract&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Install Uploader for running globally.&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;swift build -c release&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;install .build/release/uploader-cli /usr/local/bin/uploader&quot;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Users can now clone our repository and then run &lt;code&gt;swift run task install&lt;/code&gt; to install the application globally on their system. We can also provide an uninstall task, in case they wish to remove our application.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tasks&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uninstall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ParsableCommand&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            commandName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;uninstall&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            abstract&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uninstall Uploader and remove from system.&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runShell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rm -f /usr/local/bin/uploader&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;help&quot; tabindex=&quot;-1&quot;&gt;Help&lt;/h2&gt;&lt;p&gt;A really nice feature of ArgumentParser is that it generates a help message from the command structs we have created. This aids discovery of the tasks that can be executed on our project by using &lt;code&gt;swift run task -h&lt;/code&gt; or &lt;code&gt;--help&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-terminal&quot;&gt;&lt;code class=&quot;language-terminal&quot;&gt;OVERVIEW: A task runner for Uploader.

USAGE: tasks &lt;subcommand&gt;

SUBCOMMANDS:
  lint        Lint the Uploader codebase, such as static analysis.
  install     Install Uploader for running globally.
  uninstall   Uninstall Uploader and remove from system.&lt;/subcommand&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;using-this-on-ci&quot; tabindex=&quot;-1&quot;&gt;Using this on CI&lt;/h2&gt;&lt;p&gt;Now that our command line tools and automation tasks are managed using SPM, using our project on CI services such as &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt; and &lt;a href=&quot;https://bitrise.io&quot;&gt;Bitrise&lt;/a&gt; couldn&#39;t be easier. We simply call the same commands we use locally and SPM will handle checking out the correct versions, building and executing our tools.&lt;/p&gt;&lt;pre class=&quot;language-terminal&quot;&gt;&lt;code class=&quot;language-terminal&quot;&gt;swift build
swift test
swift run task lint&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Most CI services will also come with built-in support for caching, so we could speed things up by caching the SPM dependencies for future runs.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Swift Package Manager is a really great way to manage our Swift projects and it is nice being able to use the first-party official build tool and dependency manager. Now we can manage all of our automation and project command line tools using SPM as well, bringing all the project configuration together with one tool.&lt;/p&gt;&lt;p&gt;By building our automation tasks using a CLI within the project, it keeps everything together and easily discoverable. It is also great to be able to build all of this in Swift, meaning the source code and automation is all based on the same language and technologies.&lt;/p&gt;
    </content>
  </entry>  <entry>
    <title>Dealing with file extensions and Uniform Type Identifiers</title>
    <link href="https://www.lordcodes.com/articles/file-extensions-and-utis/"/>
    <updated>2019-01-18T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/file-extensions-and-utis/</id>
    <content type="html">
      &lt;p&gt;There are different ways of representing a type of file, two popular ones being file extensions and another being Uniform Type Identifiers (UTIs) from the UIKit APIs. When working with a UIKit API such as &lt;code&gt;UIDocumentPickerViewController&lt;/code&gt; we may need to distinguish between these types.&lt;/p&gt;&lt;p&gt;We can create independent types to hold file extensions and type identifiers, this makes it really clear which one is required for a particular piece of functionality.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileExtension&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; rawValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;asTypeIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TypeIdentifier&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; identifierCreated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UTTypeCreatePreferredIdentifierForTag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token constant&quot;&gt;kUTTagClassFilenameExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rawValue &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token nil constant&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; typeIdentifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; identifierCreated&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;takeRetainedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TypeIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; typeIdentifier &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TypeIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;public.data&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TypeIdentifier&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; rawValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Clear and searchable logging in Swift with OSLog</title>
    <link href="https://www.lordcodes.com/articles/swift-logging-with-oslog/"/>
    <updated>2019-01-14T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/swift-logging-with-oslog/</id>
    <content type="html">
      &lt;p&gt;When it comes to logging in Swift and iOS applications in particular, the APIs that first come to mind might be &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;NSLog&lt;/code&gt;. More recently, however, Apple has introduced a new standard for logging in the form of &lt;a href=&quot;https://developer.apple.com/documentation/os/logging&quot;&gt;unified logging&lt;/a&gt;, accessed via &lt;code&gt;OSLog&lt;/code&gt;. It is the current recommended way of logging, providing an efficient way to capture information across our applications.&lt;/p&gt;&lt;p&gt;Unified logging provides a number of improvements over previous techniques and also some differences to what we are used to.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Each message can be logged at an appropriate level, including: default, error, debug and info. They affect how messages are displayed to us and persisted.&lt;/li&gt;&lt;li&gt;Messages are grouped within subsystems and categories to enable efficient searching and filtering.&lt;/li&gt;&lt;li&gt;There is no need to wrap log statements in conditionals, due to the system being designed for performance and logs being rendered only when read.&lt;/li&gt;&lt;li&gt;User privacy is carefully respected, with dynamic string content needing to be explicitly marked as public, else they are redacted in any logs.&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;let&#39;s-get-logging&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s get logging&lt;/h2&gt;&lt;p&gt;Using unified logging from Swift is as simple as using the &lt;code&gt;os_log&lt;/code&gt; function, which we will quickly notice takes a &lt;code&gt;StaticString&lt;/code&gt; as an argument rather than a regular &lt;code&gt;String&lt;/code&gt;. The easiest way to log messages, is to place the &lt;code&gt;String&lt;/code&gt; constant directly in the function call. Extracting the message to a property is possible, however, we will need to define it&#39;s type as &lt;code&gt;StaticString&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;User signed in&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; errorMessage&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StaticString&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;404 - NOT FOUND&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Due to the &lt;code&gt;StaticString&lt;/code&gt; requirement, instead of using string interpolation we will need to use format arguments. This may feel jarring initially, however, it isn&#39;t too hard to adapt to and it provides benefits to user privacy that we will discuss a bit later on. We have access to all of the &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFStrings/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265&quot;&gt;standard format arguments&lt;/a&gt;, as well as a number of &lt;a href=&quot;https://developer.apple.com/documentation/os/logging#1682416&quot;&gt;extra value type decoders&lt;/a&gt;. The idea is that the logging system handles as much formatting for you as possible, to make the system even more efficient.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; responseCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;404 - NOT FOUND&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: %@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; logMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: &lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;&#92;(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;responseCode&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// error: cannot convert value of type &#39;String&#39;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// to expected argument type &#39;StaticString&#39;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: &lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;&#92;(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;responseCode&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;it&#39;s-good-to-be-organised&quot; tabindex=&quot;-1&quot;&gt;It&#39;s good to be organised&lt;/h2&gt;&lt;p&gt;Calls to &lt;code&gt;os_log&lt;/code&gt; can specify an &lt;code&gt;OSLog&lt;/code&gt; to use, containing a specific subsystem and category. This information is invaluable when filtering, searching and trying to understand our logs later. When the log argument isn&#39;t specified a default one is used, which has no subsystem or category configured.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; uiLog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.lordcodes.chat.ChatApp&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UI&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Contact selected&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uiLog&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; networkLog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.lordcodes.chat.ChatKit&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Network&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: %@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; networkLog&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The subsystem groups all the logs for a particular app or module, allowing us to filter for all of our own logs. From evaluating Apple&#39;s logs, the convention for subsystem is a reverse domain style, such as the Bundle Identifier of the app or framework itself. If the app is modularised into frameworks, it is a good idea to use the Bundle Identifier of the framework to split logs into their corresponding components.&lt;/p&gt;&lt;p&gt;Categories are used to group logs into related areas, to help us narrow down the scope of log messages. The convention for categories is to use human-readable names like &lt;code&gt;UI&lt;/code&gt; or &lt;code&gt;User&lt;/code&gt;. We could group logs into layers across multiple subsystems or features, such as &lt;code&gt;Network&lt;/code&gt; or &lt;code&gt;Contacts&lt;/code&gt;. Alternatively, we could group all the logs for a particular class, such as &lt;code&gt;Contacts Repository&lt;/code&gt;. It would be perfectly acceptable to combine both approaches in the same project, we should simply use the most appropriate categories to allow us to understand the context of the project&#39;s log messages.&lt;/p&gt;&lt;p&gt;We can add our different categories and subsystems as an extension of &lt;code&gt;OSLog&lt;/code&gt;, making them easily accessible across the app. Storing them in one place avoids creating &lt;code&gt;OSLog&lt;/code&gt; instances all over the codebase and helps keep the different categories in use nicely organised.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; subsystem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bundle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bundleIdentifier&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; ui &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; subsystem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UI&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; network &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; subsystem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Network&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Contact selected&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ui&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: %@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;network&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;logging-levels&quot; tabindex=&quot;-1&quot;&gt;Logging levels&lt;/h2&gt;&lt;p&gt;The unified logging system employs a set of different logging levels at which we can target different types of messages. The levels control how messages are displayed to us, how and when they are persisted and whether they are captured in different environments. How the system handles each level can even be customised through the &lt;a href=&quot;https://developer.apple.com/documentation/os/logging#2878594&quot;&gt;command-line on our machine&lt;/a&gt;. It is a good idea to use the most appropriate logging level for each message, to get the most we can out of the logging system.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Default&lt;/strong&gt;: To capture anything that might result in a failure and essentially a fall-back if no other level seems appropriate. Unless changed, messages are stored in memory buffers and persisted when they fill up.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Info&lt;/strong&gt;: To capture anything that may be useful, but is not directly used to diagnose or troubleshoot errors. Unless changed, no persistence is used, messages are just stored in memory buffers and purged as they fill up.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt;: To capture information during development to diagnose a particular issue, whilst actively debugging. They aren&#39;t captured unless enabled by a configuration change.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Error&lt;/strong&gt;: To capture application errors and failures, in particular anything critical. Messages are always persisted, to ensure they are no lost.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Fault&lt;/strong&gt;: To capture system-level or multi-process errors only, likely not of use in our app code. As with the error level, messages are always persisted.&lt;/p&gt;&lt;p&gt;Logging at each level is as simple as specifying the corresponding &lt;code&gt;OSLogType&lt;/code&gt; as an argument to the &lt;code&gt;os_log&lt;/code&gt; call.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Contact selected&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ui&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Saving contact failed&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;database&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;user-privacy&quot; tabindex=&quot;-1&quot;&gt;User privacy&lt;/h2&gt;&lt;p&gt;To ensure private user data is not accidentally persisted to application logs, which may be shared with other people, the unified logging system has a public and private argument process. By default, only scalar (boolean, integer) values are collected and dynamic strings or complex dynamic objects are redacted. If it is necessary, dynamic string arguments may be declared public and scalar arguments could also be declared private.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Contact %ld selected&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Contact %{private}ld selected&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: %@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HTTP response: %{public}@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is important we resist making all arguments public, as it could easily result in private company or user data being exposed within device logs.&lt;/p&gt;&lt;h2 id=&quot;reading-logs&quot; tabindex=&quot;-1&quot;&gt;Reading logs&lt;/h2&gt;&lt;p&gt;Whilst the debugger is attached, log messages will be shown in the Xcode console. The best way to read our logs, however, is with the Console MacOS application. Here we will be able to sort, filter and search our logs, as well as view them more easily.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Display logs in a table, making each piece of data easy to read&lt;/li&gt;&lt;li&gt;Search and filter by subsystem and category&lt;/li&gt;&lt;li&gt;Show and hide different fields for each log message&lt;/li&gt;&lt;li&gt;Turn on and off debug and info level messages&lt;/li&gt;&lt;li&gt;Save search patterns to access them more easily in the future&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Unified logging is a promising and powerful logging solution, especially when it comes to performance and filtering your log messages. Initially it might seem like it has quirks or differences to what you may be used to from &lt;code&gt;NSLog&lt;/code&gt; and &lt;code&gt;print&lt;/code&gt;. After looking a bit more and providing &lt;code&gt;os_log&lt;/code&gt; with subsystems, categories and making good use of logging levels, you will find it makes working with logs significantly easier. If you want more log coverage with better performance, you can ditch &lt;code&gt;NSLog&lt;/code&gt; and &lt;code&gt;print&lt;/code&gt; statements and start integrating &lt;code&gt;os_log&lt;/code&gt; into your apps.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;OSLog is Apple&#39;s current recommended logging approach&lt;/p&gt;&lt;/blockquote&gt;
    </content>
  </entry>  <entry>
    <title>Simpler categories when using OSLog</title>
    <link href="https://www.lordcodes.com/articles/simpler-categories-when-using-oslog/"/>
    <updated>2019-01-10T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/simpler-categories-when-using-oslog/</id>
    <content type="html">
      &lt;p&gt;Organised logging in Swift that can be searched is simple thanks to the built-in &lt;code&gt;os_log&lt;/code&gt;. By storing our categories as an extension on &lt;code&gt;OSLog&lt;/code&gt; we can access them using a short syntax.&lt;/p&gt;&lt;p&gt;This makes categories so much easier to specify and helps with auto-completion!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; logAuthentication &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.myapp.App&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Auth&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; logDatabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.myapp.App&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Database&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; logNetwork &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OSLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        subsystem&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.myapp.App&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        category&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Network&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;User signed in: %@&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logAuthentication&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Chat messages sync complete&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logNetwork&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;os_log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Chat messages saved successfully&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logDatabase&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;debug&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Create Xcode file templates and share them with your team</title>
    <link href="https://www.lordcodes.com/articles/share-xcode-file-templates/"/>
    <updated>2018-12-14T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/share-xcode-file-templates/</id>
    <content type="html">
      &lt;p&gt;Something all Xcode users will be familiar with is the process of creating new files. When the new file command is triggered, we are presented with a window containing a selection of templates to base our new file upon. These new templates often contain lines of code we immediately delete or code that needs to be changed to fit into our preferred style.&lt;/p&gt;&lt;p&gt;Many people may be unaware that instead of relying solely on the provided templates, we can create our own and have Xcode present them to us. This can simplify the process of creating new files and allow them to match more specific requirements.&lt;/p&gt;&lt;p&gt;The process of creating templates can seem a bit confusing at first, but the end result can be really useful. We are going to explore the process of writing our own Xcode file templates, before delving into how we might go about sharing these with other developers on a particular project.&lt;/p&gt;&lt;h2 id=&quot;creating-a-template&quot; tabindex=&quot;-1&quot;&gt;Creating a template&lt;/h2&gt;&lt;p&gt;When Xcode launches, it looks for file templates within a specific location: &lt;code&gt;~/Library/Developer/Xcode/Templates/File Templates&lt;/code&gt;. To get started, we need to create a directory within here that will house all of our file templates.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; ~/Library/Developer/Xcode/Templates/File&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt; Templates/Custom&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Within this directory, a quick way to get started is by copying one of the built-in templates and then altering it. They can be found within the Xcode application bundle, with a good option for Swift-based templates being the one for a new Swift file, &lt;code&gt;Source/Swift File.xctemplate&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;/Applications/Xcode.app/Contents/
  &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Developer/
    &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Library/
      &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Xcode/
        &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Templates/
          &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; File Templates/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After copying the files, we find the &lt;code&gt;xctemplate&lt;/code&gt; contains 4 different files.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;TemplateIcon.png&lt;/code&gt; and &lt;code&gt;TemplateIcon@2x.png&lt;/code&gt; are the thumbnails that are presented within the new file window. We could use these for all of our Swift templates or create specific ones of our own.&lt;/li&gt;&lt;li&gt;&lt;code&gt;TemplateInfo.plist&lt;/code&gt; is where we configure our template.&lt;/li&gt;&lt;li&gt;&lt;code&gt;___FILEBASENAME___.swift&lt;/code&gt; contains the Swift source that forms the basis of the template.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We will start by creating a template for a new Swift struct, called &lt;code&gt;Swift Struct.xctemplate&lt;/code&gt;, that is based upon the &lt;code&gt;Swift File.xctemplate&lt;/code&gt; mentioned above.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ TemplateInfo.plist&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Within the property file we can change the &lt;code&gt;Description&lt;/code&gt; and &lt;code&gt;Summary&lt;/code&gt; keys to clearly describe the template within Xcode.&lt;/p&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Description&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A Swift struct.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Summary&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A Swift struct.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ ___FILEBASENAME___.swift&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;By calling the file &lt;code&gt;___FILEBASENAME___.swift&lt;/code&gt;, the resulting Swift file will be named according to what is entered into the new file window. This same argument can be used within the template using &lt;code&gt;___FILEBASENAMEASIDENTIFIER___&lt;/code&gt;. This means that if we enter &lt;code&gt;Contact&lt;/code&gt; into the new file window, the generated file will be &lt;code&gt;Contact.swift&lt;/code&gt;, containing the struct &lt;code&gt;Contact&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;___FILEBASENAMEASIDENTIFIER___&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once completing the template, starting up Xcode and requesting a new file, we can find our template being offered within a section called &#39;Custom&#39;. The name of the section is controlled by the directory name we used within &lt;code&gt;~/Library/Developer/Xcode/Templates/File Templates&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/yi8z7Ti_rI-1470.webp 1470w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/yi8z7Ti_rI-1470.jpeg&quot; alt=&quot;Xcode new file window showing template&quot; title=&quot;Our new template shown within Xcode&quot; width=&quot;1470&quot; height=&quot;592&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;what-else-can-we-do&quot; tabindex=&quot;-1&quot;&gt;What else can we do&lt;/h2&gt;&lt;p&gt;Although they can start very basic, there are some more significant things we can do with templates.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Offer the option of Swift or Objective-C when creating a new file.&lt;/li&gt;&lt;li&gt;Change the filename based on what is entered, for example naming the file &lt;code&gt;UsersRepositoryTests&lt;/code&gt; if &lt;code&gt;UsersRepository&lt;/code&gt; is entered.&lt;/li&gt;&lt;li&gt;Ask for arguments to be entered in the new file window and then use these within the code.&lt;/li&gt;&lt;li&gt;Add file headers or copyright notices.&lt;/li&gt;&lt;li&gt;Add imports or skeleton code to be included in the file by default.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some example file templates can be found &lt;a href=&quot;https://github.com/lordcodes/lordcodes-samples/tree/master/ios/create-xcode-file-templates&quot;&gt;on GitHub&lt;/a&gt;, demonstrating some of the options available.&lt;/p&gt;&lt;h2 id=&quot;it&#39;s-nice-to-share&quot; tabindex=&quot;-1&quot;&gt;It&#39;s nice to share&lt;/h2&gt;&lt;p&gt;As we explore the possibilities that file templates provide us, one problem becomes extremely clear. It would be really great if we could create project-specific templates and share them with the other developers on the project. Although templates for a specific project are not supported automatically by Xcode, it can be done through a clever use of symbolic links.&lt;/p&gt;&lt;p&gt;We should place all templates in a directory within our project, such as &lt;code&gt;FileTemplates&lt;/code&gt;. It is likely the project is kept in source control, which will ensure the templates are tracked and shared with everyone else in the team.&lt;/p&gt;&lt;p&gt;The directory Xcode expects to find our templates should already exist if the steps were followed above. If not then we need to ensure it does.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; ~/Library/Developer/Xcode/Templates/File&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt; Templates&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once the directory exists, the symbolic link can be created here that points to the templates within our Xcode project. It is worth mentioning that if we delete the project or move it, the symbolic link can simply be deleted and recreated.&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Project Location&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;/FileTemplates &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  ~/Library/Developer/Xcode/Templates/File&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt; Templates/&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ProjectName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For example:&lt;/p&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; ~/projects/github/chatapp/FileTemplates &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  ~/Library/Developer/Xcode/Templates/File&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt; Templates/ChatApp&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After restarting Xcode, any project templates will now be presented within the &#39;New File&#39; window. It would obviously be great if Xcode could offer a solution without the extra work, however, for now it works nicely.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Xcode file templates can be a great way to get started quickly when creating new files. They are very powerful, although quite under-documented and there is much more they can do than discussed here.&lt;/p&gt;
    </content>
  </entry>  <entry>
    <title>Map the keys of a dictionary to a different type</title>
    <link href="https://www.lordcodes.com/articles/map-dictionary-keys-to-different-type/"/>
    <updated>2018-12-13T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/map-dictionary-keys-to-different-type/</id>
    <content type="html">
      &lt;p&gt;The Swift standard library includes functions to transform the values of a &lt;code&gt;Dictionary&lt;/code&gt;, we need to add one ourselves to do the same to the keys.&lt;/p&gt;&lt;p&gt;There are situations this can come in handy such as converting a &lt;code&gt;Dictionary&lt;/code&gt; of analytics event parameters from using an internal enum for the keys to using Strings for reporting to our analytics API.&lt;/p&gt;&lt;p&gt;This neat little extension will allow us to do just that!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dictionary&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;mapKeys&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NewKeyT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NewKeyT&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;rethrows&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NewKeyT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; newDictionary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NewKeyT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; forEach &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; newKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            newDictionary&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;newKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; newDictionary
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Using anchors to match a parent view&#39;s constraints</title>
    <link href="https://www.lordcodes.com/articles/using-anchors-parent-constraints/"/>
    <updated>2018-12-07T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/using-anchors-parent-constraints/</id>
    <content type="html">
      &lt;p&gt;Swift extensions are really great, including when working with Auto Layout. We can make a child view fill its superview using constraints, as well as having insets between them. This is very useful when adding a child view controller to its parent within a subview.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIView&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;attachAnchors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;to view&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; with insets&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIEdgeInsets&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zero&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;NSLayoutConstraint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;activate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            topAnchor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;constraint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                equalTo&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topAnchor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                constant&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; insets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            rightAnchor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;constraint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                equalTo&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rightAnchor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                constant&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;insets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;right&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            bottomAnchor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;constraint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                equalTo&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottomAnchor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                constant&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;insets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            leftAnchor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;constraint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                equalTo&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;leftAnchor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                constant&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; insets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;left&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Animating view colour changes</title>
    <link href="https://www.lordcodes.com/articles/animating-view-colour-changes/"/>
    <updated>2018-12-06T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/animating-view-colour-changes/</id>
    <content type="html">
      &lt;p&gt;When animating the addition of cells to a &lt;code&gt;UICollectionView&lt;/code&gt;, we may notice that text and background colours aren&#39;t animating when using &lt;code&gt;UIView.animate&lt;/code&gt;. Using &lt;code&gt;UIView.transition&lt;/code&gt; instead works perfectly!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; commentContainer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                  options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transitionCrossDissolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   commentContainer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;215&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;198&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;UIView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; commentLabel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                  options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transitionCrossDissolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   commentLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;155&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;174&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Create time intervals with explicit units</title>
    <link href="https://www.lordcodes.com/articles/time-intervals-explicit-units/"/>
    <updated>2018-12-04T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/time-intervals-explicit-units/</id>
    <content type="html">
      &lt;p&gt;In Swift, many APIs take a &lt;code&gt;TimeInterval&lt;/code&gt; instead of just a &lt;code&gt;Double&lt;/code&gt;, you need to know they are in seconds. Instead we can add functions that provide them with explicit units and allow us to convert them. It makes for a really readable call site!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token comment&quot;&gt;// Hide the calculations from the call site&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; secondsPerHour&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; secondsPerMinute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;token comment&quot;&gt;// Functions to provide time intervals with explicit units&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; secondsPerHour
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; secondsPerMinute
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// They make very readable call sites&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;TimeInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>A modular analytics layer in Swift</title>
    <link href="https://www.lordcodes.com/articles/a-modular-analytics-layer-in-swift/"/>
    <updated>2018-11-27T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/a-modular-analytics-layer-in-swift/</id>
    <content type="html">
      &lt;p&gt;There is a saying, &amp;quot;&lt;em&gt;if a tree falls in a forest and no one is around to hear it, does it make a sound?&lt;/em&gt;&amp;quot; Monitoring user behaviour is a bit like that; if people are using your app in a particular way, but you don&#39;t know about it, then how can you work out how to improve it.&lt;/p&gt;&lt;p&gt;There are many different options available to us in order to monitor user behaviour, such as user testing, collecting surveys and analytics. Here we are going to be discussing the topic of analytics, specifically using it within a Swift app.&lt;/p&gt;&lt;p&gt;When building and improving your apps, knowing how it is being used by real users &lt;em&gt;in the wild&lt;/em&gt; can be very valuable. It allows you to make data-informed decisions rather than just estimating what you think is a good idea. You can also use it to verify and test out ideas once they have been released to your users.&lt;/p&gt;&lt;p&gt;Whilst adding analytics to an app can be quick and easy, ensuring the implementation is easy to use, alter and extend can be more complex. The implementation should be able to stand the test of time and give us the flexibility to make changes to the analytics data we are reporting in the future. We are going to look through one way of building an analytics layer in Swift, that is both modular and extensible.&lt;/p&gt;&lt;h2 id=&quot;backend&quot; tabindex=&quot;-1&quot;&gt;Backend&lt;/h2&gt;&lt;p&gt;When analytics data is captured within our apps, we would normally want to submit this to our preferred backend. This allows data to be collected over time and analysis to be ran over the data.&lt;/p&gt;&lt;p&gt;It is very common for this backend to be a third-party SDK such as: &lt;a href=&quot;https://firebase.google.com/docs/analytics/get-started?platform=ios&quot;&gt;Firebase Analytics&lt;/a&gt; or &lt;a href=&quot;https://docs.mixpanel.com/docs/tracking-methods/sdks/swift&quot;&gt;MixPanel&lt;/a&gt;. You may also want to use a tool such as &lt;a href=&quot;https://segment.com/docs/connections/sources/catalog/libraries/mobile/ios/&quot;&gt;Segment&lt;/a&gt;, to control where the data is sent and have the flexibility to change the destination whenever you want.&lt;/p&gt;&lt;p&gt;Your backend may be an in-house analytics system, reporting data to your own backend API or pumping data into a data warehouse of some kind. This can be beneficial if your data is specialised or you need to do something with it that the third-party destinations don&#39;t support.&lt;/p&gt;&lt;p&gt;Whichever backend solution has been settled on, it is good to wrap its API in one of your own, to avoid the codebase being littered with a specific analytics API. Doing this will give you the flexibility to change the solution more easily and help make your code more maintainable.&lt;/p&gt;&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;Features&lt;/h2&gt;&lt;p&gt;We are going to build a layer that avoids using a static API, puts any backend APIs behind a protocol, uses the power of Swift enums and pairs each event with the pieces of data it needs to contain.&lt;/p&gt;&lt;p&gt;More specifically it should:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Be easy to report new and existing events.&lt;/li&gt;&lt;li&gt;Allow the data be sent to whichever analytics backend we wish to use, even multiple.&lt;/li&gt;&lt;li&gt;Be testable and mockable, allowing it to be an injected dependency.&lt;/li&gt;&lt;li&gt;Allow events to be reported from anywhere in the app, but encourage best practices.&lt;/li&gt;&lt;li&gt;Have compile-time safety of events and their properties.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There are a few different components that make up our analytics layer, each covering part of the process.&lt;/p&gt;&lt;h2 id=&quot;the-main-event&quot; tabindex=&quot;-1&quot;&gt;The main event&lt;/h2&gt;&lt;p&gt;The events themselves can be modelled through our &lt;code&gt;AnalyticsEvent&lt;/code&gt; enum.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Equatable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; addContactTapped
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contactSelected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;messageSent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threadType&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; userSignedIn
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The enum contains a case for each event we want to fire, with associated values for any pieces of data that need to be attached to the event. When we report an event, we are required to provide any data it needs. By writing events in this way we can reduce the amount of code required to report an event, whilst checking for correctness at compile time.&lt;/p&gt;&lt;p&gt;When the event is passed further it provides the set of parameters that are attached to it. These parameters use an enum for their names, to allow them to be mapped differently later on, similar to the events themselves.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; parameters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addContactTapped&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userSignedIn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contactSelected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contactIndex&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;describing&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;messageSent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threadType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;threadType&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; threadType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rawValue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;messageLength&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;describing&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Equatable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; contactIndex
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; messageLength
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; threadType
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For writing the switch statement over the &lt;code&gt;AnalyticsEvent&lt;/code&gt; enum it is best to avoid using a default case, as this enforces that each new event is handled.&lt;/p&gt;&lt;h2 id=&quot;providers&quot; tabindex=&quot;-1&quot;&gt;Providers&lt;/h2&gt;&lt;p&gt;Each backend you wish to report data to will conform to our &lt;code&gt;AnalyticsProvider&lt;/code&gt; protocol. This will document the different analytics operations we can perform.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;report(event:)&lt;/code&gt; function is taking our event enum as an argument. This allows each provider to map the event to whichever format they need it in. For example, Firebase Analytics requires events to contain underscores (_) instead of hyphens (-). Once the event has been mapped, it would then be reported to the destination for that particular provider, often calling through to the provider&#39;s SDK.&lt;/p&gt;&lt;p&gt;A final solution may also report screens, user properties, preferences and more. These would be added to the &lt;code&gt;AnalyticsProvider&lt;/code&gt; protocol.&lt;/p&gt;&lt;h2 id=&quot;let&#39;s-implement-a-provider&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s implement a provider&lt;/h2&gt;&lt;p&gt;Making our backend conform to the provider protocol is relatively simple, let&#39;s start by building one for Firebase Analytics. The event name and parameters are mapped to strings, before being passed through to the Firebase Analytics SDK &lt;code&gt;logEvent&lt;/code&gt; function.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FirebaseAnalyticsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; eventMapper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEventMapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; eventMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; parameters &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; eventMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Analytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;logEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; parameters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; parameters&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The flexibility of the solution means we can easily build another provider to log events to the console.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LoggingAnalyticsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; eventMapper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEventMapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; eventMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Event reported: &lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;&#92;(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can create a provider for whichever destination we wish to use.&lt;/p&gt;&lt;h2 id=&quot;get-mapping&quot; tabindex=&quot;-1&quot;&gt;Get mapping&lt;/h2&gt;&lt;p&gt;Each provider needs to convert the event enum into a reporting format. Most analytics SDKs require events in a string format and so it an be a good idea to provide a default mapper that does this.&lt;/p&gt;&lt;p&gt;If a particular app doesn&#39;t need the flexibility for each provider to control the mapping, we can instead return data in the correct format directly within the &lt;code&gt;AnalyticsEvent&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For now we will give ourselves full flexibility, by using a separate mapper.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEventMapper&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first part to the mapping process is to get a name for the event. This is as simple as using a switch statement to map each event case to a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;eventName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; event &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addContactTapped&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;addContact_tapped&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contactSelected&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;contact_selected&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;messageSent&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message_sent&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userSignedIn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;user_signedIn&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second part is getting a dictionary of event parameters.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; newParameters &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parameters&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;forEach &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; newKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parameterName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        newParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;newKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; newParameters
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;parameterName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; parameter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; parameter &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contactIndex&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;contact_index&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;messageLength&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message_length&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;threadType&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;thread_type&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;parameters(for:)&lt;/code&gt; function is simply converting the dictionary keys from an enum to a &lt;code&gt;String&lt;/code&gt;. If used in multiple places, it can be easily extracted to a generic extension on &lt;code&gt;Dictionary&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;putting-it-all-together&quot; tabindex=&quot;-1&quot;&gt;Putting it all together&lt;/h2&gt;&lt;p&gt;We now need to bring together all of the components we have built and create the API for our analytics layer, the &lt;code&gt;AnalyticsReporter&lt;/code&gt;. The reporter is the dependency you will be injecting and using throughout your app to report events.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsReporter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; providers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;providers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;providers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; providers
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        providers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;forEach &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This reporter allows multiple analytics providers to be used, obviously if an app only required a single provider we could decide whether this was worth supporting or not. Due to each analytics backend being wrapped with our provider, the reporter is pretty simple.&lt;/p&gt;&lt;p&gt;As with the provider, a final solution may also include reporting of other entities such as screens and user properties.&lt;/p&gt;&lt;h2 id=&quot;time-to-use-it&quot; tabindex=&quot;-1&quot;&gt;Time to use it&lt;/h2&gt;&lt;p&gt;We can now put our implementation into practice to see how it is to use.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ContactsViewModel&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; coordinator&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ContactsCoordinator&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; analyticsReporter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsReporter&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coordinator&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ContactsCoordinator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; analyticsReporter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsReporter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coordinator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; coordinator
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;analyticsReporter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; analyticsReporter
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;contactSelected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;at index&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        analyticsReporter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contactSelected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        coordinator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startContactThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;at&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;addContactTapped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        analyticsReporter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addContactTapped&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        coordinator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startContactCreation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;AnalyticsReporter&lt;/code&gt; can be injected wherever we wish to use it, in the case above in a &lt;code&gt;ContactsViewModel&lt;/code&gt;. Using the API is as simple as selecting the correct event and providing any values it requires.&lt;/p&gt;&lt;p&gt;If we need to report a new event, we just need to add it to the &lt;code&gt;AnalyticsEvent&lt;/code&gt; enum, provide its parameters and update any mapping code. ⚒&lt;/p&gt;&lt;h2 id=&quot;testing&quot; tabindex=&quot;-1&quot;&gt;Testing&lt;/h2&gt;&lt;p&gt;It is very important that our analytics code be testable and that it doesn&#39;t make any other code more difficult to test. To verify the correct events have been reported, we can create a &lt;code&gt;TestingAnalyticsProvider&lt;/code&gt; within our unit test sources. The test provider stores reported events so that they can be asserted on afterwards.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TestingAnalyticsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsProvider&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; eventsReported &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        eventsReported&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;That wraps up implementing, using and testing our new analytics layer. In general the approach we have put forward is flexible and can be altered where necessary to suit a particular app&#39;s needs.&lt;/p&gt;&lt;p&gt;We have seen that:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Our implementation uses a modular approach that should minimise the impact analytics has on the rest of the app.&lt;/li&gt;&lt;li&gt;It is easy to configure and report both new and existing events.&lt;/li&gt;&lt;li&gt;Each destination is wrapped in a provider protocol, giving the flexibility to support any backend we wish to use, including a test one.&lt;/li&gt;&lt;li&gt;By avoiding a static API, we encourage the reporter dependency to be instantiated or provided via dependency injection, whilst it still being easy to do so.&lt;/li&gt;&lt;li&gt;The use of an enum for the event type enforces compile-time safety for events and the properties they each require.&lt;/li&gt;&lt;/ul&gt;
    </content>
  </entry>  <entry>
    <title>Protocol functions with default parameter values</title>
    <link href="https://www.lordcodes.com/articles/protocol-functions-default-parameters/"/>
    <updated>2018-11-26T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/protocol-functions-default-parameters/</id>
    <content type="html">
      &lt;p&gt;Being able to specify default parameter values in Swift allows us to reduce the number of function overloads in our code. For protocols it is still possible as long as we use an extension and delegate to the version without the default values.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;showError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorViewControllerDelegate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt;  &lt;span class=&quot;token class-name&quot;&gt;ErrorController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;showError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorViewControllerDelegate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token nil constant&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;showError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ContactsViewController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIViewController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;showError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorViewControllerDelegate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorController&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ContactsViewController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
contacts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;I don&#39;t need a delegate.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Access the call site of a function using special Swift literals</title>
    <link href="https://www.lordcodes.com/articles/access-call-site-swift-literals/"/>
    <updated>2018-11-26T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/access-call-site-swift-literals/</id>
    <content type="html">
      &lt;p&gt;Accessing information about the call site of a function is surprisingly simple in Swift by simply using &lt;code&gt;#file&lt;/code&gt;, &lt;code&gt;#function&lt;/code&gt; and &lt;code&gt;#line&lt;/code&gt;. This can be a great help when we want to put assertions within a shared function or print text without losing the original context.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt;  &lt;span class=&quot;token class-name&quot;&gt;XCTestCase&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UnexpectedNilError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;unwrapAssert&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValueT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              message&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Unexpected nil&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              file&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StaticString&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token literal constant&quot;&gt;#file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              line&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token literal constant&quot;&gt;#line&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValueT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;XCTFail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt;  &lt;span class=&quot;token class-name&quot;&gt;UnexpectedNilError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Safely index items within a collection</title>
    <link href="https://www.lordcodes.com/articles/safely-index-items-within-a-collection/"/>
    <updated>2018-11-25T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/safely-index-items-within-a-collection/</id>
    <content type="html">
      &lt;p&gt;We can make some great things with extensions in Swift, as well as subscript functions. This one allows us to safely access collection elements by index, getting back an optional instead of errors being thrown!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Collection&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;subscript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;safe&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        indices&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token nil constant&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; numbers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
numbers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 4&lt;/span&gt;
numbers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// nil, no error&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Managing secrets within an iOS app</title>
    <link href="https://www.lordcodes.com/articles/managing-secrets-within-an-ios-app/"/>
    <updated>2018-11-20T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/managing-secrets-within-an-ios-app/</id>
    <content type="html">
      &lt;p&gt;Almost all iOS apps need private values, such as API keys, secrets and passwords. Some of these may need to be used in the source code, to setup third-party SDKs or backend APIs. Some secrets may be needed during the build process or to use developer tools, such as communicating with an Apple Developer account.&lt;/p&gt;&lt;p&gt;Simple approaches for including secrets into an app would include: putting values directly into the code, placing them into build scripts or keeping them in the &lt;code&gt;Info.plist&lt;/code&gt; file. Unfortunately, these approaches mean the secrets are committed to source control and are visible to anyone with access to the the code. Furthermore, scripts and plist files added to the app bundle can be extracted from the compiled app.&lt;/p&gt;&lt;p&gt;We are going to look through some more secure ways of managing secrets within our iOS projects, in order to access them from code. It is worth noting that it is practically impossible to keep anything within an app 100% secret, as apps are &amp;quot;out in the wild&amp;quot; on users&#39; devices. A good approach is to enforce a suitable level of protection for the situation, for example a banking app should probably have a higher level of security than a to-do list app.&lt;/p&gt;&lt;h2 id=&quot;control-the-sources&quot; tabindex=&quot;-1&quot;&gt;Control the sources&lt;/h2&gt;&lt;p&gt;It is important to keep secrets out of source control for both open and closed source projects for various reasons.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;By committing secrets to source control, you are sharing these values with all users who have read-access to the repository, including anyone who gets access in the future. You may have users who need to access the project, but not necessarily use all of the secrets.&lt;/li&gt;&lt;li&gt;After a user checks out the repository, they would gain a copy of all the secrets stored on their local machine.&lt;/li&gt;&lt;li&gt;If your source control system is compromised, not only would the source code be obtained, so would all of the passwords and other secrets.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Git allows us to include a &lt;code&gt;.gitignore&lt;/code&gt; file, where we can list files (or expressions) that should be kept out. If these files are required by our app, each developer just creates these files and adds any required values. We could include template versions of these files in Git or a guide for what is needed in documentation, including contact details for who to provide secrets if they are required.&lt;/p&gt;&lt;h2 id=&quot;cocoapods-keys&quot; tabindex=&quot;-1&quot;&gt;Cocoapods Keys&lt;/h2&gt;&lt;p&gt;As most iOS developers are aware, many iOS projects use &lt;a href=&quot;https://github.com/CocoaPods/CocoaPods&quot;&gt;Cocoapods&lt;/a&gt; as a dependency manager. Cocoapods includes a plugin system that allows its processes to be hooked into. One such plugin that can be used to manage your app secrets securely is &lt;a href=&quot;https://github.com/orta/cocoapods-keys&quot;&gt;cocoapods-keys&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Not only does cocoapods-keys keep the secrets out of the project sources, it holds them securely in your system keychain. When pods are installed or updated, the developer is asked for each key that has no value already stored. An Objective-C class is generated that contains obfuscated versions of keys and their values. As this class is built by running Cocoapods, the &lt;code&gt;Pods/CocoaPodsKeys&lt;/code&gt; directory can be added to the &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The plugin has many advantages:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;It asks for a value to be provided for each key, avoiding the need to document the required secrets. This makes it very easy for each developer to get their project environment configured.&lt;/li&gt;&lt;li&gt;The source file is generated, which allows it to be easily kept out of source control.&lt;/li&gt;&lt;li&gt;Secrets are scrambled within the generated sources, to protect against the keys being extracted from the app binary.&lt;/li&gt;&lt;li&gt;It can be used from both Swift and Objective-C sources.&lt;/li&gt;&lt;li&gt;By reading from the keychain, we could access the secrets within build scripts if we needed to.&lt;/li&gt;&lt;li&gt;We can share keys between different projects that use cocoapods-keys.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;let&#39;s-setup-our-keys&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s setup our keys&lt;/h2&gt;&lt;p&gt;Incorporating cocoapods-keys into our project is very simple and starts with including the plugin into our &lt;code&gt;Podfile&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;plugin &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cocoapods-keys&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:project&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ChatApp&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:target&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ChatApp&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:keys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ChatAPIClientSecretProd&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ChatAPIClientSecretTest&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AnalyticsWriteKey&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After we next run &lt;code&gt;pod install&lt;/code&gt;, we will be asked to enter the value for each of our keys listed above. Once all keys are configured, the plugin will generate a source file that can be referenced in our code to read the keys.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Keys&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatAppKeys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Analytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;analyticsWriteKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For values like our backend API secret, where we may want it to be different for debug and release, we can include both keys and then read a different one at runtime. There are obviously many different ways of handling this, depending on the exact use case we have. Therefore, we aren&#39;t going to discuss all possible options here and will simply look at switching based on whether the app is built in the debug configuration.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; apiClientSecret &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token directive property&quot;&gt;&lt;span class=&quot;token directive-name&quot;&gt;#if&lt;/span&gt; DEBUG&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;chatApiClientSecretTest
    &lt;span class=&quot;token directive property&quot;&gt;&lt;span class=&quot;token directive-name&quot;&gt;#else&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;chatApiClientSecretProd
    &lt;span class=&quot;token directive property&quot;&gt;&lt;span class=&quot;token directive-name&quot;&gt;#endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you are using Cocoapods in your project, I would recommend looking into &lt;a href=&quot;https://github.com/orta/cocoapods-keys&quot;&gt;cocoapods-keys&lt;/a&gt; over other options, due to it being a secure and easy-to-use way to solve the problem.&lt;/p&gt;&lt;h2 id=&quot;doing-things-ourselves&quot; tabindex=&quot;-1&quot;&gt;Doing things ourselves&lt;/h2&gt;&lt;p&gt;Many projects don&#39;t use Cocoapods or we may not want to use a plugin and so we can also consider implementing a solution ourselves. Secrets will be passed into the build process, where they will be made available as environment variables. We can then read these variables and use them to generate a source file that will give our code access to our secret values.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;We can have different values for different environments&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Xcode offers &lt;em&gt;xcconfig&lt;/em&gt; files that can be linked to a particular build configuration in order to load in settings specified within them. An xcconfig file can be specified for each build configuration, allowing us to have different values for each environment. We may wish to point our app at our production API for release apps, but a test backend for debug apps.&lt;/p&gt;&lt;p&gt;Note that if a particular app doesn&#39;t need different values depending on the build configuration, we can use a shell script instead of the xcconfig files and source the file into our final build phase later on.&lt;/p&gt;&lt;p&gt;We start off by creating example versions of our xcconfig files. If we place these files within a directory such as &lt;code&gt;BuildConfig&lt;/code&gt; it will keep them separate from other project files. It is recommended to include these files into the project, so that they appear within Xcode, but we should ensure they aren&#39;t added to any targets within the &lt;em&gt;Target Membership&lt;/em&gt; area of the &lt;em&gt;File Inspector&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ debug.example.xccconfig&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET_TEST&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ release.example.xccconfig&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET_PROD&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By duplicating and renaming the example files we can easily create the &lt;em&gt;real&lt;/em&gt; files that will be used by the project. As with the example files, we want these files in the project, but not attached to any targets.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ debug.xccconfig&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;123456789&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abcdefgh&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ release.xccconfig&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;CHAT_API_CLIENT_SECRET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;987654321&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ANALYTICS_WRITE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abcdefgh&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To avoid the real xcconfig files being added to source control, they should be listed in the &lt;em&gt;.gitignore&lt;/em&gt; file. We can use a regular expression in the rule to catch the files for all configurations.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;BuildConfig/*.example.xcconfig
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The final step, is telling Xcode to use our xcconfig files, which is specified within the project file under &lt;code&gt;Info → Configurations&lt;/code&gt;. Make sure to select an xcconfig for each build configuration and for the target you need.&lt;/p&gt;&lt;h2 id=&quot;generating-the-source&quot; tabindex=&quot;-1&quot;&gt;Generating the source&lt;/h2&gt;&lt;p&gt;When Xcode builds your project, the values in the xcconfig files are made available as environment variables. You could simply use these values in your &lt;code&gt;Info.plist&lt;/code&gt; file if you wished with the form &lt;code&gt;$(CHAT_API_CLIENT_SECRET)&lt;/code&gt;. We have already discussed that putting secrets into plist files isn&#39;t very secure, but have mentioned it for completeness.&lt;/p&gt;&lt;p&gt;We are going to generate a source file using a tool called &lt;a href=&quot;https://github.com/krzysztofzablocki/Sourcery&quot;&gt;Sourcery&lt;/a&gt; and then reference this source file in our code to access our secrets. Needless to say, we will need to start by adding &lt;a href=&quot;https://github.com/krzysztofzablocki/Sourcery&quot;&gt;Sourcery&lt;/a&gt; to our project, for example including a standalone version within our repository or using Cocoapods.&lt;/p&gt;&lt;p&gt;Sourcery uses a template system, where we create a stencil file to show the tool how to generate our code. We will create &lt;code&gt;AppSecrets.stencil&lt;/code&gt; including some syntax to substitute in the secret values when the file is generated from the template.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppSecrets&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; chatApiClientSecret&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ argument.chatApiClientSecret }}&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; analyticsWriteKey&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ argument.analyticsWriteKey }}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We next need to add a build phase to our project by selecting the project file, then selecting the correct target and going to the Build Phases tab.&lt;/p&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Tools/Sourcery/bin/sourcery
    &lt;span class=&quot;token parameter variable&quot;&gt;--sources&lt;/span&gt; Sources
    &lt;span class=&quot;token parameter variable&quot;&gt;--templates&lt;/span&gt; Templates/AppSecrets.stencil
    &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; Generated
    &lt;span class=&quot;token parameter variable&quot;&gt;--args&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;chatApiClientSecret&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$CHAT_API_CLIENT_SECRET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&quot;,
           &lt;span class=&quot;token assign-left variable&quot;&gt;analyticsWriteKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ANALYTICS_WRITE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&quot;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The path to the Sourcery executable will depend on how it is installed.&lt;/li&gt;&lt;li&gt;The sources argument needs to be specified, even though it isn&#39;t used in this situation. We can simply point it to our main sources, or any valid directory.&lt;/li&gt;&lt;li&gt;The templates argument is a path from the root of the project to our template file.&lt;/li&gt;&lt;li&gt;The output directory is where the generated source file is written. We need to ensure this folder exists, possibly by adding &lt;code&gt;mkdir -p Generated&lt;/code&gt; at the start of the build phase.&lt;/li&gt;&lt;li&gt;Within args, values are separated by commas in the form: &lt;code&gt;arg1=one,arg2=two&lt;/code&gt;. It is a good idea to escape as above incase the secret values contain any special characters.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We can use &lt;a href=&quot;https://gist.github.com/lordcodes/f9bd45773f1872516bb3e2aaee45cd3f&quot;&gt;a more complex script&lt;/a&gt; instead of manually specifying secrets within the build phase. This can be beneficial if there are more than a couple of secrets or the build phase is hard to maintain.&lt;/p&gt;&lt;p&gt;After adding the build phase, we can build the app as normal and then add the generated &lt;code&gt;AppSecrets.swift&lt;/code&gt; file to the project so that it is compiled and linked to the project target. As with the xcconfig files, we should add &lt;code&gt;AppSecrets.swift&lt;/code&gt; to our &lt;em&gt;.gitignore&lt;/em&gt; file to keep it out of Git.&lt;/p&gt;&lt;p&gt;Using secrets within our code is as simple as referencing our generated struct.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Analytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;with&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;analyticsWriteKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;The goal we wanted to achieve was being able to reference secret values within our source code, without these values themselves needing to be kept in source control. The two solutions we have looked at are quite different, but both achieve the same goal.&lt;/p&gt;&lt;p&gt;By using cocoapods-keys, we can avoid the manual setup and also avoid the values being stored in plain-text anywhere in the project. However, our solution using Sourcery can be used without Cocoapods and will still require very little maintenance. There will definitely be even more solutions available online for more use cases, it will come down to using the most appropriate solution for the situation.&lt;/p&gt;
    </content>
  </entry>  <entry>
    <title>Sharing accessibility identifiers between app and tests</title>
    <link href="https://www.lordcodes.com/articles/sharing-accessibility-ids-app-and-tests/"/>
    <updated>2018-11-16T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/sharing-accessibility-ids-app-and-tests/</id>
    <content type="html">
      &lt;p&gt;For identifying views within UI tests we can use accessibility identifiers, which are &lt;code&gt;String&lt;/code&gt; values. We can register all of our identifiers within an enum, using an extension to set them on our views. By adding the enum to the app target and the UI test target, an extension can be added to find views within tests suing our ID enum. It&#39;s really nice to use an enum, avoiding duplicating the strings and avoiding errors!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;App sources&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIAccessibilityIdentification&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; viewAccessibilityIdentifier&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ViewAccessibilityIdentifier&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fatalError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Not implemented&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            accessibilityIdentifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newValue&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rawValue
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

addContactButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;viewAccessibilityIdentifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addContactButton&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Test sources&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XCUIElementQuery&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;subscript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ViewAccessibilityIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XCUIElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rawValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;XCUIApplication&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buttons&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;addContactButton&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Protocol function that returns the Self type</title>
    <link href="https://www.lordcodes.com/articles/protocol-function-return-self-type/"/>
    <updated>2018-11-12T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/protocol-function-return-self-type/</id>
    <content type="html">
      &lt;p&gt;We may find situations in which we want a protocol function to return the current type, here the metatype &lt;code&gt;Self&lt;/code&gt; can come in handy. In these situations rather than just returning the protocol type, we likely want to return the type that conforms to the protocol. An associated type can be added to the protocol that defaults to &lt;code&gt;Self&lt;/code&gt; to achieve this. Pretty handy!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatThreadsRobot&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;associatedtype&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatThreadsType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatThreadsRobot&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Self&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;tapCreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatThreadsType&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConnectionThreadsRobot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatThreadsRobot&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;tapCreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConnectionThreadsRobot&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buttons&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;createThreadButton&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Using metatype Self to return current type</title>
    <link href="https://www.lordcodes.com/articles/metatype-self-to-return-current-type/"/>
    <updated>2018-11-09T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/metatype-self-to-return-current-type/</id>
    <content type="html">
      &lt;p&gt;A helpful keyword in Swift is &lt;code&gt;Self&lt;/code&gt;, which is a metatype that represents the current type. The current type may be the class, subclass or current implementer of a protocol, depending on where it is used.&lt;/p&gt;&lt;p&gt;A handy use-case for it is to avoid specifying generic placeholder types. Neat!&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadRobot&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CallerT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CallerRobot&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XCUIApplication&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;tapCompleteButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;otherElements&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;actionButtonRail&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buttons&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Complete&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>  <entry>
    <title>Constraints for a child view controller within a subview</title>
    <link href="https://www.lordcodes.com/articles/child-view-controller-subview-constraints/"/>
    <updated>2018-10-23T00:00:00Z</updated>
    <id>https://www.lordcodes.com/articles/child-view-controller-subview-constraints/</id>
    <content type="html">
      &lt;p&gt;When a &lt;code&gt;UIViewController&lt;/code&gt; is added within one of it&#39;s parent&#39;s subviews, there can be an issue where it doesn&#39;t expand to fill it. This can often happen when we only tested on a specific device size.&lt;/p&gt;&lt;p&gt;The fix involves preventing the auto-resizing mask from being turned into constraints and ensuring the child view controller&#39;s anchor constraints are all attached to the edge&#39;s of its container view.&lt;/p&gt;&lt;pre class=&quot;language-swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;addChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;child&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
containerView&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addSubview&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;translatesAutoresizingMaskIntoConstraints &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachAnchors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; containerView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;didMove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toParent&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry></feed>