<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.zestyrobustcode.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.zestyrobustcode.com/" rel="alternate" type="text/html" /><updated>2026-06-22T02:20:47+00:00</updated><id>https://www.zestyrobustcode.com/feed.xml</id><title type="html">Zesty Robust Code</title><subtitle>Ruminations on iOS development and other things.</subtitle><author><name>Wade Weitzel</name></author><entry><title type="html">The Agentic Development Factory</title><link href="https://www.zestyrobustcode.com/ai/the_ai_factory/" rel="alternate" type="text/html" title="The Agentic Development Factory" /><published>2026-06-21T00:00:00+00:00</published><updated>2026-06-21T00:00:00+00:00</updated><id>https://www.zestyrobustcode.com/ai/the_ai_factory</id><content type="html" xml:base="https://www.zestyrobustcode.com/ai/the_ai_factory/"><![CDATA[<p>What is software development in 2026…</p>

<p>In the (far too recent) past, the practice of software engineering involved getting the specifications for a product, implementing those specs and iterating on the product as needs changed.  With the advent of agentic development harnesses such as Claude Code, that world has changed.  Many organizations have taken the approach of letting their engineers figure out how best to leverage those tools.  This has led to fragmented approaches across development teams.  This fragmentation comes with a hefty price.  Token usage is not optimized, beneficial multipliers obtained from a common approach are lost, and lots of redundant investigation amongst devs is happening.  As the new tools have entered our workflows, we’ve forgotten about the principles of software engineering that have served us for decades.</p>

<p>As I’ve thought about this problem, it’s become clear to me that a unified approach to development is required.  As engineers, it is our desire to find the fastest, most unique ways to exploit the tools as quickly as possible.  This is not that.  Instead of describing what new skill file you should create or which CLAUDE.md practice you should use: I suggest we start by redefining the entire development cycle.  Development cycles must vary between teams, but there is certainly a subset of common patterns that can apply to all teams.  I’m not making a unique observation by saying software engineering in 2026 is about becoming the architects, maintainers and operators of software factories.  We must walk before we run, so how do we apply this “factory” concept?</p>

<h3 id="what-are-the-properties-of-a-factory">What Are The Properties of a Factory</h3>

<ul>
  <li>It runs on raw material.</li>
  <li>It configures itself to the product being built.</li>
  <li>It has a defined production line.</li>
  <li>It keeps records of the work it has done.</li>
  <li>It has quality-control gates.</li>
  <li>It detects and responds to defects.</li>
  <li>It separates production from inspection.</li>
  <li>It has humans at control points.</li>
  <li>It constantly improves.</li>
</ul>

<p>Consider a company that makes a small plastic toy dog.  They decide to build a second factory to create a small plastic toy cat.  The new factory might not be exactly the same factory as the old one.  We can expect it to be very similar.  Software development is no different.  Our agentic factory is the base template we will reuse and configure each time we create a factory to deliver new software product.</p>

<h3 id="basic-properties-of-our-factory">Basic Properties of Our Factory</h3>

<h4 id="the-factory-runs-on-tokens">The Factory Runs on Tokens</h4>

<p>Our factory runs on tokens.  Tokens are a limited and costly resource, so the factory should be designed to maximize the value we get from the token spend.</p>

<p>This does not mean minimizing token usage at all costs.  It means using tokens intentionally, where they improve speed, quality, understanding, or delivery.  Engineers should never be measured on token spend (high or low); they should be measured on the product the factory delivers.</p>

<h4 id="we-own-what-the-factory-produces">We Own What the Factory Produces</h4>

<p>That means we own the quality of the code.  More importantly, we own the quality of the product delivered to customers.  AI-generated work is not exempt from engineering standards, review, testing, maintainability, or product responsibility.</p>

<h4 id="documentation-becomes-more-important">Documentation Becomes More Important</h4>

<p>The value of documentation increases when we are writing less of the code manually.</p>

<p>The agent needs context to operate effectively.  Future engineers need context to understand what was built.  Good documentation improves both the output of the factory and our ability to maintain that output after it is produced.</p>

<h4 id="claude-code-is-just-one-component-of-the-factory">Claude Code is Just One Component of the Factory</h4>

<p>It is not the entire factory, and the entire factory does not live inside Claude Code.</p>

<p>The factory includes our repositories, documentation, plans, prompts, tests, review processes, CI/CD systems, human judgment, and team standards.</p>

<h4 id="the-factory-works-best-when-used-consistently">The Factory Works Best When Used Consistently</h4>

<p>Some parts of the factory, such as generated documentation, shared conventions, reusable prompts, review patterns, and planning artifacts, only become valuable if we use them consistently across the team.</p>

<h4 id="the-factory-can-be-extended">The Factory Can Be Extended</h4>

<p>You can add to the factory.</p>

<p>Factory additions may be local to your machine, workflow, or repository.  If an addition proves useful, please communicate it so the team can decide whether it should become part of the shared factory.</p>

<h4 id="the-factory-will-change-quickly">The Factory Will Change Quickly</h4>

<p>Claude Code may change.  AI tools may change.  Our repositories may change.  Our team may change.  Our processes may change.</p>

<p>The factory must be able to adapt quickly without losing its core purpose: producing high-quality software in a repeatable, inspectable, and improvable way.</p>

<h3 id="the-factory-loop">The Factory Loop</h3>

<p><img src="/assets/images/SoftwareFactory.jpg" alt="The Factory Loop" /></p>

<p><em>This section will assume we are using Claude Code.  Other agent harnesses fit into this just as well.</em></p>

<p>The factory executes in a loop.  It defines how we prepare, plan, review, submit, and QA each task we run through the factory.  Here, a task is defined as a piece of product large enough to release to production.  It may contain many subtasks.  If we are thinking about Claude Code, a task is something big enough that we are going to run plan mode on it.</p>

<h4 id="system-prepare">System Prepare</h4>

<p>Every machine in your organization running the factory must have common elements needed to support the factory.  These could be software items (Claude Code, for example), additional plugins and tools, processes, etc.  This should all be documented in a known location (or better yet, scripted to auto-install).</p>

<p>Some recommendations on defining this step:</p>

<ul>
  <li>Define the common software required by your team.</li>
  <li>Recommend “Quality of Life” extensions for Claude Code.
    <ul>
      <li>Is there a recommendation for the format of the status bar?</li>
      <li>What are common elements of the home directory CLAUDE.md everyone should use?</li>
      <li>Is there a security setup to prevent Claude Code from doing certain unsafe actions?</li>
      <li>What hooks and skills are useful enough to be recommended always for everyone on the team?</li>
      <li>Are there things we can do to make searching through dependencies faster and cheaper?  Define them in this step.</li>
    </ul>
  </li>
  <li>How do we handle workspace management?</li>
</ul>

<h5 id="understand-your-requirements">Understand Your Requirements</h5>

<p>Before defining your system prepare step, it is essential to understand your requirements and limitations.  If your organization is limited on token spend, you may want to compromise speed and model accuracy to optimize for cost (or at least be certain everyone knows how to save tokens).  If you are token-maxing, you don’t care about spend (you will not be reading this anyway).  As those core requirements and limitations change, so will your system prepare step.  It’s easy to research how to optimize Claude Code.  It’s harder to figure out how to optimize it for what you care about.  We need to optimize not just Claude Code, but the entire factory.</p>

<h5 id="workspace-management">Workspace Management</h5>

<p>Workspace management can be useful for systems with lots of repos and/or microservices.  Most people will store those in a common folder.  My favorite pattern is to run Claude Code in the repo I’m working on, but to keep a CLAUDE.md in my workspace folder that maps what each repo is called, where it is located, and what it does (at least for the important ones).  This makes it easy to direct Claude Code to go searching through repos for information on dependencies.</p>

<h5 id="not-a-one-time-step">Not A One-Time Step</h5>

<p>You will notice that I put this as the entry point into the factory loop, not outside it.  This is the step where you should analyze the factory to determine if you should tweak it.  With AI, nothing is deterministic and things change fast.  You should be constantly re-evaluating goals and re-evaluating whether or not the factory achieves them.</p>

<h4 id="task-prepare">Task Prepare</h4>

<p>Task preparation generally includes how you set up your repo and how you begin the process of agentic development in Claude Code.  This step also features the most important prompt of the loop, because each execution loop that follows will be based on this plan.</p>

<h5 id="repo-level-claudemd-and-plan-management">Repo-level CLAUDE.md and Plan Management</h5>

<p>What elements should every repo-level CLAUDE.md include?  This CLAUDE.md should be written or tweaked in this step.  As a project changes, it is a good idea to visit this often to be sure it stays up to date.  This is also where I like to add plan file management.</p>

<p>I like to add a section to this CLAUDE.md (for most repos, which is why I put it in the repo-level CLAUDE.md) that tells Claude how to create a plan file for every ticket (Jira or otherwise) being worked on.  This instruction tells Claude how to name the file (I use the Jira ticket, a date, and a short description), and to store it in a <code class="language-plaintext highlighter-rouge">plans</code> folder.  It instructs Claude to keep the file up to date as we implement subtasks that change the original plan.  This is useful for both documentation and context management.  If the plan file is always up to date, I am free to clear my context confidently because the plan file is always there with the essential information about what we are implementing.  It creates fantastic documentation to understand what happened when a ticket was implemented.  You can even feed the old plan into Claude to give it context in the future if necessary.</p>

<p>Much has been written about how to create a good CLAUDE.md.  I won’t cover those details here, other than to mention that it is the core of your context.  It gets written into the context each time.  Its brevity and accuracy are vital.</p>

<h5 id="the-model-and-effort">The Model and Effort</h5>

<p>It is important to establish what model and effort you want to use.  The quality of the planning session will have a big influence on how the rest of the implementation goes.  For me, it’s the place I spend the tokens on Opus.  I will drop to Sonnet for implementation.  I use the recommended effort levels (usually high, but it’s changed over time per model).</p>

<h5 id="the-prompt">The Prompt</h5>

<p>For planning, you really should be giving Claude Code the specification of what you are trying to develop.  We are clearly going to a place where spec-based agentic harnesses will automatically pull in the specs to start.  If you are still doing this manually, it can be good to create the prompt in a different editor and not in the Claude Code CLI.  I write a short document (and paste it into the CLI when finished) that includes things like:</p>

<ul>
  <li>What do we need to accomplish?</li>
  <li>What are the constraints?</li>
  <li>Are there areas we just want to scaffold or do we want to implement everything now?</li>
  <li>What are the testing expectations?  How do we prove we got it right?</li>
  <li>Are other repos involved?  Do I need to tell Claude where to find background information it may need?</li>
</ul>

<h4 id="execute-loop">Execute Loop</h4>

<p>When we execute, we enter a sub-loop. While the default behavior is to tell Claude to implement the entire plan after it is generated, I often find it useful to break implementation into smaller subtasks. This reduces my cognitive load when reviewing Claude’s work and gives me opportunities to bench test changes locally as I go.</p>

<p>The right approach depends on the task. If the work is small and well-defined, I have no problem letting Claude implement it all at once, which effectively means I only make a single pass through the execution loop. As mentioned earlier, this is also where I typically switch to Sonnet.</p>

<p>The first step is context management. Because we maintain a plan file throughout the process, I will often clear or compact the conversation context before starting the next subtask. Having context usage visible in my status bar helps me decide when to do this. The idea is simple: if the context window is full of details from previous subtasks, I can flush that information and have Claude Code reload the necessary context from the plan file. This maximizes the amount of context available for the current task and theoretically reduces token spend.  It is difficult to prove that this consistently produces better outcomes because nothing about LLM behavior is fully deterministic. That said, I have had good results with this approach.</p>

<p>Now that I’ve prepared the context, I prompt Claude to implementation the subtask, including unit tests.</p>

<p>When implementation is complete, I review the change in a diff tool.  I’ve found VS Code to be my favorite option.  If I see something I don’t like, I either change it myself or ask Claude Code about it.</p>

<p>Next is the bench test.  I run the change and verify it behaves as expected.  If it doesn’t, either Claude Code or I fix the issue and repeat the process.</p>

<p>After that, it’s on to the next subtask or on to the review loop.  As important as implementation is, the execution loop is intentionally simple. Most of the thinking has already been done during planning. The goal here is simply to execute, verify, and iterate until the plan is complete.</p>

<h4 id="review-loop">Review Loop</h4>

<p>The review loop is a sub-loop we run when execution is complete.  The idea is that we perform a code review in Claude Code prior to opening a PR.  The loop is fairly simple.  We start by running an agentic code review.  We only need to do this once.  When that is complete, we review each issue.  If desired, we can compact or clear the context and then fix the issue.  Once the current issue is fixed, we move on to the next issue until all issues are skipped or fixed.</p>

<h5 id="code-review-skill">Code Review Skill</h5>

<p>I highly recommend finding a multi-agent code review skill.  There are many solutions for this, and it isn’t hard to write your own to customize it.  The one I use is a custom four agent review tool.  The first agent looks for correctness.  The second focuses on security.  The third focuses on concurrency.  The final subagent reviews testability and maintainability.  It creates an MD file that lists each error, categorizes it by severity and confidence, and suggests a fix.  I run the tool and then open the MD file and fix the issues, one at a time.  The tool is very thorough and somewhat expensive to run, even under Sonnet.  I’ve deemed the time and token spend to be worth it because it does a great job at catching issues before they reach other team members, testers, or even customers.  I get a very detailed review before the PR is even created.</p>

<h4 id="submit-loop">Submit Loop</h4>

<p>The submit sub-loop is the last barrier before the code is allowed to be committed and merged.  We start by creating a PR.  Assuming you are using GitHub, it can be good to run it through a CoPilot review if available.  It adds a second review of your code separate from the big multi-agent review executed in the Review Loop.  Overall, I think it is an optional step that has benefits if you can afford it.  I fix the issues it finds and then request a manual review.  If that results in issues, I fix those as well.  Once approved, we merge to master/main.  This is also the time I perform the retrospective.</p>

<h5 id="retrospective-system">Retrospective System</h5>

<p>Retrospectives are a tricky thing in Claude Code because of the way it manages context.  As part of constantly improving my factory, I want Claude’s opinion on what went well and what went poorly during a session.  I have a system set up for this.  It uses a hook to store a journal of every meaningful Claude Code “turn”.  It is based on the Jira ticket, so it can span multiple sessions and context clears.  A retro command is provided, which, when run, uses Haiku to create an MD file that tells you what went wrong, what could have been better, and suggestions on how to improve accuracy and cost.  We use Haiku because we want this to be inexpensive.  Each time I run the retro I look for tweaks I can make to improve my factory.  The retro has gotten me to update my skill files, change the way I manage context, and alter my CLAUDE.md files.  Note that this is different from a traditional Agile-style retro.  It is looking at the Claude Code process and not the entire task.</p>

<h4 id="qarelease-loop">QA/Release Loop</h4>

<p>Finally, we are ready for a QA cycle.  We start by creating and/or running automated tests.  We follow that with manual testing and a cycle to fix any issues that may arise.  As we finish looping through issue fixing we come to the point where we release the code to production, regression test, and let the user have at it.  This completes a pass through the loop.</p>

<h3 id="conclusion">Conclusion</h3>

<p>Those well ensconced in the world of AI may take a look at this and deem it outdated or rudimentary.  Many organizations are still struggling with these basics.  Consider the idea of building, saving, and checking in a plan file for each ticket.  If every engineer on a team generates those plan files, your documentation base grows and becomes consistent.  If we all review code in the same way, it improves our confidence in the code AI is producing.  This baseline confidence allows us to automate more of the things.  The multiplier effect then becomes apparent.  We start delivering faster, better code.  There are no revelations here.  That said, what is presented here is a plan.  Like anything in software engineering, the better your plan, the better your results.</p>

<p><em>Photo taken at the top of 401 Trail, Crested Butte Colorado</em></p>]]></content><author><name>Wade Weitzel</name></author><category term="ai" /><category term="ai" /><category term="agentic" /><category term="claude" /><category term="factory" /><summary type="html"><![CDATA[What is software development in 2026…]]></summary></entry><entry><title type="html">Unit Testing Static Methods In Swift</title><link href="https://www.zestyrobustcode.com/swift/unit_testing_static_methods_in_swift/" rel="alternate" type="text/html" title="Unit Testing Static Methods In Swift" /><published>2020-05-28T18:24:03+00:00</published><updated>2020-05-28T18:24:03+00:00</updated><id>https://www.zestyrobustcode.com/swift/unit_testing_static_methods_in_swift</id><content type="html" xml:base="https://www.zestyrobustcode.com/swift/unit_testing_static_methods_in_swift/"><![CDATA[<p>Understanding How To Unit Test Static Methods Written In Swift Or Objective-C</p>

<p>One of the challenges I’ve run into as an Objective-C dev transitioning to Swift is the additional difficulty of unit testing in Swift.  Objective-C is a highly dynamic language, which makes it easy to mock, stub and spy on just about anything.  Swift – not so much.  The easy one-line doubles suddenly become manual mocks.  This is especially true for singletons and static methods.  Many times, our Swift code will need to use third-party libraries that leverage singletons and static  methods, or even access them from our legacy codebase.  Fortunately, these are still testable, with a few caveats.</p>

<p>To begin, we will start with an admittedly contrived example (Available on GitHub: <a href="https://github.com/weitzel926/StaticMethods">Static Methods on Github</a>).  The UI features a label and a button.  When you press the button, a manager class returns a string that welcomes the user as an American or a Briton based on where they are located and the local time.  The manager class itself is not really necessary.  What it is doing could be done more easily directly in the ViewController, but separating it will let us focus on the unit test of static methods without UI unit testing getting in the way.</p>

<h3 id="setting-up-an-example-to-test">Setting Up An Example To Test</h3>

<p>The pieces of this system are as follows:</p>

<p><strong>ObjectiveCStaticUtils</strong> - Objective-C class that contains a static method which tells us whether this is the US or UK version of the app and returns the result as an NSString.</p>

<figure class="highlight"><pre><code class="language-objectivec" data-lang="objectivec"><span class="k">+</span> <span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="n">getAppVersionType</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="s">@"US"</span><span class="p">;</span>
    
<span class="c1">//     return @"UK";</span>
<span class="p">}</span></code></pre></figure>

<p><strong>SwiftStaticUtils</strong> - Swift class that has static methods which return the welcome message for each version type, customized for whether the current time is AM or PM as a Swift String.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">SwiftStaticUtils</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUSMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">guard</span> <span class="k">let</span> <span class="nv">hour</span> <span class="o">=</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="nf">getHour</span><span class="p">()</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome American"</span>
        <span class="p">}</span>
        
        <span class="k">if</span> <span class="n">hour</span> <span class="o">&lt;=</span> <span class="mi">12</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome American AM"</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome American PM"</span>
        <span class="p">}</span>
        
    <span class="p">}</span>
    
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUKMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">guard</span> <span class="k">let</span> <span class="nv">hour</span> <span class="o">=</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="nf">getHour</span><span class="p">()</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome Briton"</span>
        <span class="p">}</span>
        
        <span class="k">if</span> <span class="n">hour</span> <span class="o">&lt;=</span> <span class="mi">12</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome Briton AM"</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Welcome Briton PM"</span>
        <span class="p">}</span>
    <span class="p">}</span>
    
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getHour</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Int</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="kt">Date</span><span class="p">()</span>
        <span class="k">let</span> <span class="nv">dateComponents</span> <span class="o">=</span> <span class="kt">Calendar</span><span class="o">.</span><span class="n">current</span><span class="o">.</span><span class="nf">dateComponents</span><span class="p">([</span><span class="o">.</span><span class="n">hour</span><span class="p">],</span> <span class="nv">from</span><span class="p">:</span> <span class="n">date</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">dateComponents</span><span class="o">.</span><span class="n">hour</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p><strong>MessageManager</strong> - Swift class that has an instance method that returns the message as directed by the two utility classes.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">MessageManager</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">getMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">if</span> <span class="kt">ObjectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"US"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="nf">getUSMessage</span><span class="p">()</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="kt">ObjectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"UK"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="nf">getUKMessage</span><span class="p">()</span>
        <span class="p">}</span>
        
        <span class="k">return</span> <span class="s">"Welcome Mystery User"</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>The ViewController creates an instance of MessageManager and calls getMessage() on the button tap handler to get the string for the label.  Simple enough.  We will assume that ObjectiveCStaticUtils and SwiftStaticUtils are a library we don’t own and both have previously been unit tested.</p>

<h3 id="setting-up-a-prototype-for-the-tests">Setting Up A Prototype For The Tests</h3>

<p>To begin, we setup a new unit test case class for MessageManager, called MessageManagerTests.swift.  We can add one prototype test and be sure that the setup works.  This test should pass.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">XCTest</span>
<span class="kd">@testable</span> <span class="kd">import</span> <span class="kt">StaticMethods</span>

<span class="kd">class</span> <span class="kt">MessageManagerTests</span><span class="p">:</span> <span class="kt">XCTestCase</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">test_getMessage</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">XCTAssert</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Now, if we look at the getMessage method, there are three cases we need to test for:</p>

<ol>
  <li>The app version type is US</li>
  <li>The app version type is UK</li>
  <li>The app version type is something else</li>
</ol>

<p>Since we made the assumption that the other methods are unit tested, we know we need three tests.  We will have to control the output from getAppVersionType, getUSMessage, and getUKMessage in order to write reliable tests.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">MessageManagerTests</span><span class="p">:</span> <span class="kt">XCTestCase</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">test_getMessage_us</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">XCTAssert</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="kd">func</span> <span class="nf">test_getMessage_uk</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">XCTAssert</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="kd">func</span> <span class="nf">test_getMessage_somethingElse</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">XCTAssert</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<h3 id="faking-the-swift-static-methods">Faking The Swift Static Methods</h3>

<p>Let’s start inside out, and control the output of the static methods written in Swift.  “Dependency injection” can be used to allow us to replace the static methods the MessageManager uses with custom ones specific for our test.  Dependency injection simply means to write your code in a way that you can change (or “inject”) your dependencies.  In order to do this, we will need to inject SwiftStaticUtils as a type (as opposed to an instance of some type, because SwiftStaticUtils is just a class with static methods).  Swift provides a special <a href="https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID455">MetaType type</a> that can help us achieve this.  The metatype can represent any class, enumeration or structure type.  In our case, the metatype for SwiftStaticUtils is SwiftStaticUtils.Type.  Given this, we now have a hook we can use to inject SwiftStaticUtils as a type, so we can control our class methods.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">MessageManager</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">swiftStaticUtils</span><span class="p">:</span><span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="k">Type</span> <span class="o">=</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="k">self</span>
    
    <span class="kd">func</span> <span class="nf">getMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">if</span> <span class="kt">ObjectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"US"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">swiftStaticUtils</span><span class="o">.</span><span class="nf">getUSMessage</span><span class="p">()</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="kt">ObjectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"UK"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">swiftStaticUtils</span><span class="o">.</span><span class="nf">getUKMessage</span><span class="p">()</span>
        <span class="p">}</span>
        
        <span class="k">return</span> <span class="s">"Welcome Mystery User"</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>To prepare for injecting the type, we create and initialize a member variable in our MessageManager to hold the metatype.  We can then use the member variable to call the static methods.  So, the injection is ready.  Now we need to write a fake.  In order to write a fake, we need create a <a href="https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID521">protocol extension</a> that both our fake and SwiftStaticUtils conform to.  To do this, we create a new protocol, SwiftStaticUtilsProtocol.  SwiftStaticUtilsProtocol belongs to our code, not our tests.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">protocol</span> <span class="kt">SwiftStaticUtilsProtocol</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUSMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUKMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">SwiftStaticUtils</span> <span class="p">:</span> <span class="kt">SwiftStaticUtilsProtocol</span> <span class="p">{}</span></code></pre></figure>

<p>Here, we define a new protocol with two static methods (Note, we left out getHour() because we don’t need to control what it returns for our test).  We then add an extension to SwiftStaticUtils which means that SwiftStaticUtils conforms to SwiftStaticUtilsProtocol.  Said another way, it means that SwiftStaticUtils has a getUSMessage() and a getUKMessage() method, and we can refer to an instance of SwiftStaticUtils as an instance of SwiftStaticUtilsProtocol.  We can change our member variable in MessageManager to reflect this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">var</span> <span class="nv">swiftStaticUtils</span><span class="p">:</span><span class="kt">SwiftStaticUtilsProtocol</span><span class="o">.</span><span class="k">Type</span> <span class="o">=</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="k">self</span></code></pre></figure>

<p>If you rerun the code, it still works.  Now we can make a manual fake that conforms to SwiftStaticUtilsProtocol and inject it.  We will add FakeSwiftStaticUtils to our test code:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">@testable</span> <span class="kd">import</span> <span class="kt">StaticMethods</span>

<span class="kd">class</span> <span class="kt">FakeSwiftStaticUtils</span> <span class="p">:</span> <span class="kt">SwiftStaticUtilsProtocol</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUSMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">"Testing US"</span>
    <span class="p">}</span>
    
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getUKMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">return</span> <span class="s">"Testing UK"</span>
    <span class="p">}</span>
<span class="p">}</span> </code></pre></figure>

<p>We have to import the StaticMethods module so we can see SwiftStaticUtilsProtocol, and implement the two static methods from the protocol.  I give them different return values than the actual code so I am 100% sure the data is coming from my tests, not from the code.  We will now be able to create an instance of FakeSwiftStaticUtils and assign it to the swiftStaticUtils member variable in MessageManager for our tests.</p>

<h3 id="stubbing-the-objective-c-static-method">Stubbing The Objective-C Static Method</h3>

<p>Before we can put it all together, we still need to deal with the Objective-C static method.  Our code in MessageManager can react to the value of getAppVersionType in three ways.  It behaves differently if getAppVersionType returns “US”, “UK”, or something else.  In order to test all these scenarios, we need to force the static method to return a different value in each of our tests.  We will start by creating another protocol extension and fake.  In the code, we create ObjectiveCStaticUtilsProtocol.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">protocol</span> <span class="kt">ObjectiveCStaticUtilsProtocol</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">ObjectiveCStaticUtils</span> <span class="p">:</span> <span class="kt">ObjectiveCStaticUtilsProtocol</span> <span class="p">{}</span></code></pre></figure>

<p>Because ObjectiveCStaticUtils is an Objective-C class, you can expect some automatic renaming and type shuffling to occur, as it would if you imported your Objective-C class to Swift.  It can sometimes be handy to just temporarily override your Objective-C class to get Xcode to show you the method signatures.  In this case, note that getAppVersionType returns String, not NSString.</p>

<p>With the protocol in place, we can again change MessageManager to use it:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">MessageManager</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">swiftStaticUtils</span><span class="p">:</span><span class="kt">SwiftStaticUtilsProtocol</span><span class="o">.</span><span class="k">Type</span> <span class="o">=</span> <span class="kt">SwiftStaticUtils</span><span class="o">.</span><span class="k">self</span>
    <span class="k">var</span> <span class="nv">objectiveCStaticUtils</span><span class="p">:</span><span class="kt">ObjectiveCStaticUtilsProtocol</span><span class="o">.</span><span class="k">Type</span> <span class="o">=</span> <span class="kt">ObjectiveCStaticUtils</span><span class="o">.</span><span class="k">self</span>
    
    <span class="kd">func</span> <span class="nf">getMessage</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">objectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"US"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">swiftStaticUtils</span><span class="o">.</span><span class="nf">getUSMessage</span><span class="p">()</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="n">objectiveCStaticUtils</span><span class="o">.</span><span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">==</span> <span class="s">"UK"</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">swiftStaticUtils</span><span class="o">.</span><span class="nf">getUKMessage</span><span class="p">()</span>
        <span class="p">}</span>
        
        <span class="k">return</span> <span class="s">"Welcome Mystery User"</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>…and create a fake, FakeObjectiveCStaticUtils in the test code…</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">@testable</span> <span class="kd">import</span> <span class="kt">StaticMethods</span>

<span class="kd">class</span> <span class="kt">FakeObjectiveCStaticUtils</span> <span class="p">:</span> <span class="kt">ObjectiveCStaticUtilsProtocol</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">stubbedAppVersion</span><span class="p">:</span><span class="kt">String</span><span class="p">?</span>
    
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">getAppVersionType</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">stubbedAppVersion</span><span class="o">!</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>In addition to implementing getAppVersionType(), we also add a static variable called the “stubbedAppVersion.”  We can set this static variable before calling getAppVersionType() to control what getAppVerisonType() returns.  It has to be static so our static method can access it.  Now, all we have to do is inject our two fakes and write our test methods.</p>

<h3 id="putting-it-all-together">Putting It All Together</h3>

<p>Given that all of our tests have the same dependencies, we can avoiding repeating ourselves (some folks will refer to this as DRY - Don’t Repeat Yourself) and initialize our fakes in our setup and teardown methods of our test case.  The test will be run in this order:  setup() is called, the test is executed, tearDown() is called.  This happens with each test.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"> <span class="k">var</span> <span class="nv">fakeSwiftStaticUtils</span><span class="p">:</span> <span class="kt">FakeSwiftStaticUtils</span><span class="o">.</span><span class="k">Type</span><span class="o">!</span>
 <span class="k">var</span> <span class="nv">fakeObjectiveCStaticUtils</span><span class="p">:</span> <span class="kt">FakeObjectiveCStaticUtils</span><span class="o">.</span><span class="k">Type</span><span class="o">!</span>
    
 <span class="k">var</span> <span class="nv">messageManager</span><span class="p">:</span> <span class="kt">MessageManager</span><span class="o">!</span>
    
 <span class="k">override</span> <span class="kd">func</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>
     <span class="n">messageManager</span> <span class="o">=</span> <span class="kt">MessageManager</span><span class="p">()</span>
     
     <span class="n">fakeSwiftStaticUtils</span> <span class="o">=</span> <span class="kt">FakeSwiftStaticUtils</span><span class="o">.</span><span class="k">self</span>
     <span class="n">messageManager</span><span class="o">.</span><span class="n">staticUtils</span> <span class="o">=</span> <span class="n">fakeSwiftStaticUtils</span>
     
     <span class="n">fakeObjectiveCStaticUtils</span> <span class="o">=</span> <span class="kt">FakeObjectiveCStaticUtils</span><span class="o">.</span><span class="k">self</span>
     <span class="n">messageManager</span><span class="o">.</span><span class="n">objectiveCStaticUtils</span> <span class="o">=</span> <span class="n">fakeObjectiveCStaticUtils</span>
 <span class="p">}</span>
 
 <span class="k">override</span> <span class="kd">func</span> <span class="nf">tearDown</span><span class="p">()</span> <span class="p">{</span>
     <span class="n">fakeObjectiveCStaticUtils</span><span class="o">.</span><span class="n">stubbedAppVersion</span> <span class="o">=</span> <span class="s">"NONE"</span>
     
     <span class="n">fakeSwiftStaticUtils</span> <span class="o">=</span> <span class="kc">nil</span>
     <span class="n">fakeObjectiveCStaticUtils</span> <span class="o">=</span> <span class="kc">nil</span>
 <span class="p">}</span></code></pre></figure>

<p>Much like in the code, we create two member variables using the metatype of the fake classes.  We also create the messageManager variable that is the instance we will be testing (call me crazy, but I find ‘sut’ more jarring to read than a named variable with context – do as you will).  In the setUp method, we initialize the metatype variables to the types of our two fakes and inject them into the MessageManager.  The types in MessageManager are protocol types, so this is entirely valid.  Because we defined the variables in the MessageManager with initial values, this code will override those initial values, and inject what we want.</p>

<p>For cleanup, we set our variables back to nil.  I also like to set the stubbedAppVersion in the FakeObjectiveCStaticUtils class to a nonsense value.  Usually when we stub, we are creating brand new instances of objects, and can let local scoping or the setUp and tearDown methods clean up for us.  In this case, because we are stubbing a static, the variable that holds the stub value has to be static too, so it is on us to be sure it gets re-initialized to a value we aren’t testing for.</p>

<p>Now let’s look at the tests:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">func</span> <span class="nf">test_getMessage_us</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">fakeObjectiveCStaticUtils</span><span class="o">.</span><span class="n">stubbedAppVersion</span> <span class="o">=</span> <span class="s">"US"</span>
  
  <span class="kt">XCTAssertEqual</span><span class="p">(</span><span class="n">messageManager</span><span class="o">.</span><span class="nf">getMessage</span><span class="p">(),</span> <span class="s">"Testing US"</span><span class="p">)</span>
<span class="p">}</span>

<span class="kd">func</span> <span class="nf">test_getMessage_uk</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">fakeObjectiveCStaticUtils</span><span class="o">.</span><span class="n">stubbedAppVersion</span> <span class="o">=</span> <span class="s">"UK"</span>
  
  <span class="kt">XCTAssertEqual</span><span class="p">(</span><span class="n">messageManager</span><span class="o">.</span><span class="nf">getMessage</span><span class="p">(),</span> <span class="s">"Testing UK"</span><span class="p">)</span>
<span class="p">}</span>

<span class="kd">func</span> <span class="nf">test_getMessage_somethingElse</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">fakeObjectiveCStaticUtils</span><span class="o">.</span><span class="n">stubbedAppVersion</span> <span class="o">=</span> <span class="s">"NOWHERE"</span>
  
  <span class="kt">XCTAssertEqual</span><span class="p">(</span><span class="n">messageManager</span><span class="o">.</span><span class="nf">getMessage</span><span class="p">(),</span> <span class="s">"Welcome Mystery User"</span><span class="p">)</span>
<span class="p">}</span></code></pre></figure>

<p>The tests are easy now!  We just need to verify the message returns what we expect the stub to return, and include the error case.  We have successfully injected a fake for our Swift and Objective-C class of static methods and unit tested the method that uses them!</p>

<h3 id="the-downside-to-this">The Downside To This</h3>

<p>One of the general benefits to unit testing is the idea that if our code is testable, it is better code.  In this case, I believe we have made the code itself worse in order to test it.  Some will claim that using protocol extensions for injectable dependencies such as these makes a more flexible system, which is true.  However, that flexibility comes at the expense of extra indirection and complexity.  This makes the code needlessly complex and more difficult to understand for flexibility we likely will never need.  The chances are far higher that this code will confuse a fellow developer than it will provide a magic solution to a future problem we don’t have.  That said, if we want to unit test, this is our choice.</p>

<p>The obvious answer is to avoid static methods like this.  This is not always possible when dealing with systems that have libraries you don’t control and are full of legacy code.  As with most things, there is no free lunch.  You can test this, but it does come with a few drawbacks.  As engineers, we have to balance those tradeoffs to make our codebase better.</p>]]></content><author><name>Wade Weitzel</name></author><category term="swift" /><category term="swift" /><category term="json" /><category term="decodable" /><summary type="html"><![CDATA[Understanding How To Unit Test Static Methods Written In Swift Or Objective-C]]></summary></entry><entry><title type="html">Decoding JSON with Decoder in Swift</title><link href="https://www.zestyrobustcode.com/swift/decoding_json_with_decoder_in_swift/" rel="alternate" type="text/html" title="Decoding JSON with Decoder in Swift" /><published>2020-03-27T00:24:03+00:00</published><updated>2020-03-27T00:24:03+00:00</updated><id>https://www.zestyrobustcode.com/swift/decoding_json_with_decoder_in_swift</id><content type="html" xml:base="https://www.zestyrobustcode.com/swift/decoding_json_with_decoder_in_swift/"><![CDATA[<p>A deep dive into the Decoder protocol…</p>

<p>To say parsing JSON in Swift is annoying is a bit of an understatement.  For those of us used to Objective-C’s more loose typing, parsing JSON was as simple as making your data models initialize themselves with an NSDictionary.  The strong typing of Swift removes this flexibility.  Recently (well, not SUPER recently - Swift 4, to be precise), a protocol was added which makes JSON parsing easier, with some hard to understand caveats.</p>

<p>In the process of adding Swift to a large Objective-C app, I was unable to find documentation that describes how this works in one place, so I will attempt to solve that here.  In addition, this system uses many Swift concepts so it is a useful exercise for an Objective-C dev looking to understand Swift better.</p>

<p>Swift is an open source project, and one can look directly at the source code for the JSON APIs.  Most of the relevant bits related to JSON are included in the following file: <a href="https://github.com/apple/swift/blob/master/stdlib/public/Darwin/Foundation/JSONEncoder.swift">JSONEncoder</a></p>

<p>These APIs include both decoding (turning JSON into Swift data structures) and encoding (turning your Swift data structures into JSON).  This post discusses decoding.</p>

<h3 id="jsondecoder">JSONDecoder</h3>

<p>Apple documentation: <a href="https://developer.apple.com/documentation/foundation/jsondecoder">JSON-Decoder</a></p>

<p>The JSONDecoder takes JSON objects and turns them into Swift data type instances (and includes some ways to configure how this is accomplished).  The key method to this is:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">func</span> <span class="n">decode</span><span class="o">&lt;</span><span class="kt">T</span><span class="o">&gt;</span><span class="p">(</span><span class="kt">T</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="kt">Data</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">T</span></code></pre></figure>

<p>To use this, your code would look something like this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">instanceOfMyDataModel</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="n">typeOfMyDataModel</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">json</span><span class="p">)</span></code></pre></figure>

<p>This is pretty straightforward, even with the generics.  The JSONDecoder is initialized, after which you can use the decode method to generate an instance of your data model.  It takes the type of your data model and the JSON as a parameter.  The JSON is of type Data, which is just a byte buffer in UTF-8 format.  After it decodes, it returns an instance of your type.  There are plenty of things that can throw errors here, so we need to put this is in a try block.</p>

<h3 id="string-to-data">String to Data</h3>

<p>Consider the following JSON:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">json</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
   "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">"
   "</span><span class="n">description</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>There are two things to be aware of.  You will often see the “””<Some String="">””” literal format for JSON because it allows you to format your JSON in a readable way directly in your code.  This is handy for texts like this or using small chunks of JSON in a playground.  Most of the time, you will be getting your JSON from the network.  Secondly, the data method is converting the string into a UTF-8 encoded Data instance.  It has the following signature:</Some></p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">func</span> <span class="nf">data</span><span class="p">(</span><span class="n">using</span> <span class="nv">encoding</span><span class="p">:</span> <span class="kt">String</span><span class="o">.</span><span class="kt">Encoding</span><span class="p">,</span> <span class="nv">allowLossyConversion</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">false</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Data</span><span class="p">?</span></code></pre></figure>

<p>If you went and looked at the Swift String struct documentation expecting to find this method, you were probably surprised it wasn’t there.  The data method is actually defined in <a href="https://developer.apple.com/documentation/swift/stringprotocol">StringProtocol</a>, which String (and SubString) conform to.  So, it’s there, but tricky to find in the documentation. If you look at the code, you will also see it is in a different place as well.</p>

<p>Open a new playground and add this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">string</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(</span><span class="s">"test"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>You should find that this compiles and runs fine.  Now add the following:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">nsstring</span> <span class="o">=</span> <span class="kt">NSString</span><span class="p">(</span><span class="s">"test"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">data2</span> <span class="o">=</span> <span class="n">nsstring</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>This fails to compile with a type UInt has no member ‘utf8’ error.  What is happening here gives us insight into why this works behind the scenes.  The compile error can be fixed with the following modification:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">data2</span> <span class="o">=</span> <span class="n">nsstring</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="kt">String</span><span class="o">.</span><span class="kt">Encoding</span><span class="o">.</span><span class="n">utf8</span><span class="o">.</span><span class="n">rawValue</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>So, for an NSString instance, the code is bridged from Objective-C, which gives a different signature because it is an entirely different type.  There is typically no reason to use NSString in Swift code, but this is confusing because some of the String methods you are accustomed to (like the data method) are not documented in the String class, they are in StringProtocol.</p>

<h3 id="the-json-spec">The JSON spec</h3>

<p>One should also be aware that a mapping like what we know on the iOS side as a “dictionary” is called an “object” in the <a href="https://www.json.org/json-en.html">JSON specification</a>.  For the remainder of this document, we will refer to them only as “dictionaries”, but it may be helpful to note the difference.</p>

<h3 id="codable--decodable">Codable &amp; Decodable</h3>

<p>Swift provides two protocols to parse (Decodable) and build (Encodable) JSON.  The Codable protocol represents both Encodable &amp; Decodable.  When you use Decodable you will usually end up using Codable.  It is defined as:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">public</span> <span class="kd">typealias</span> <span class="kt">Codable</span> <span class="o">=</span> <span class="kt">Encodable</span> <span class="o">&amp;</span> <span class="kt">Decodable</span></code></pre></figure>

<p>We now have some JSON and we know which protocol we need to parse it.  We also know the basics of using JSONDecoder.  It is time to look at our data model.  Consider the following playground:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
   "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
   "</span><span class="n">price</span><span class="s">": 1.50,
   "</span><span class="n">description</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Product</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span></code></pre></figure>

<p>This is similar to what we have already seen, except that we define a struct called “Product” that conforms the Decodable protocol (by conforming to Codable).  This is our data model.  If we execute this, we will get a valid instance of Product, based on the jsonData instance.</p>

<p>Decodable itself is available in <a href="https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift">Codable.swift</a> and looks like:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">@_implicitly_synthesizes_nested_requirement</span><span class="p">(</span><span class="s">"CodingKeys"</span><span class="p">)</span>
<span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span>
<span class="p">}</span></code></pre></figure>

<p>Thus, the only thing you must implement for Decodable is the init(from decoder:) method.  But…wait…we didn’t implement this did we?  If we peer into the <a href="https://developer.apple.com/documentation/swift/decodable/2894081-init">documentation</a> we can see that a default implementation is provided.  How is that?  Welp, gentle coder, you should not worry yourself about such things.  The compiler actually generates this for you with the Decodable protocol.  Consider it magic, consider it a bunch of C++ code you don’t want to read – just know that on this one, the compiler has got your back.</p>

<h3 id="problem---json-has-poor-naming---introducing-coding-keys">Problem - JSON Has Poor Naming - Introducing Coding Keys</h3>

<p>Perhaps the most common problem that will cause our JSON to map poorly to our data model is the naming of key values inside of our JSON.  Fortunately, Codable has a Coding Keys scheme that can help us use the names we want in our code.  Let’s start by understanding how this works in the default case, and then build on that to customize our property names with respect to JSON.</p>

<p>There is another piece of compiler sorcery in our playground, and it has to do with how the system knows the names of your JSON keys map to the properties in your data model.  If you modify your data model in your playground to the following code you should see that things still compile and execute as expected:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>   
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"name"</span>
      <span class="k">case</span> <span class="n">sku</span> <span class="o">=</span> <span class="s">"sku"</span>
      <span class="k">case</span> <span class="n">price</span> <span class="o">=</span> <span class="s">"price"</span>
      <span class="k">case</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"description"</span>
   <span class="p">}</span>
    
   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span></code></pre></figure>

<p>The CodingKeys enum is a special nested enum that conforms to the CodingKey protocol (We will get to why you may need to know this later).  CodingKeys is not a reserved name, you can name the enum whatever you want, although CodingKeys is very common.  This enum provides the mapping between properties and keys.  Alternatively, when you get to encoding this data model, the encoder will ONLY encode the properties it has coding keys for.</p>

<p>It should be noted that this all working depends on your properties being of types that conform to Codable.  In Codable.swift, you can see the extensions to types to support Codable, such as Int below (You will find these in Codable.swift):</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">extension</span> <span class="kt">Int</span><span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
      <span class="k">self</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">singleValueContainer</span><span class="p">()</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Int</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="p">}</span>

   <span class="kd">public</span> <span class="kd">func</span> <span class="nf">encode</span><span class="p">(</span><span class="n">to</span> <span class="nv">encoder</span><span class="p">:</span> <span class="kt">Encoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
      <span class="k">var</span> <span class="nv">container</span> <span class="o">=</span> <span class="n">encoder</span><span class="o">.</span><span class="nf">singleValueContainer</span><span class="p">()</span>
      <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">encode</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<h3 id="how-do-codingkeys-work">How do CodingKeys Work?</h3>

<p>CodingKeys is just the typical name of the enum you use that conforms to the CodingKey protocol, so a more appropriate question would be how does CodingKey work?  To find out, the best reference is the Swift proposal for Codable which was eventually implemented (<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md">Swift proposal</a>) in Swift 4.</p>

<p>CodingKey itself is a protocol that defines what a type needs to do in order to be used as a key.  The protocol is very simple:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">CodingKey</span> <span class="p">:</span> <span class="kt">CustomDebugStringConvertible</span><span class="p">,</span> <span class="kt">CustomStringConvertible</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">stringValue</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
   <span class="nf">init</span><span class="p">?(</span><span class="nv">stringValue</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span>

   <span class="k">var</span> <span class="nv">intValue</span><span class="p">:</span> <span class="kt">Int</span><span class="p">?</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
   <span class="nf">init</span><span class="p">?(</span><span class="nv">intValue</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span>
<span class="p">}</span></code></pre></figure>

<p>It contains a stringValue and an initializer that takes a string for keys (for collections that have named elements) and an intValue with an Int initializer (for collections that are indexed).  It is always possible (we will work an example below) to customize your own CodingKey instance for your own purposes.  So, how do we get from the enum above to a CodingKey?</p>

<p>The short answer:  the compiler does it for us.  It will generate an enum that conforms to CodingKey.  It will override the stringValue (or intValue) getter to return the correct value based on what you provided in the enum.  The link above for the swift archival serialization proposal will show you a sample generated class, if you are curious.  The decoder, whether you are using the compiler-generated default or you implemented it yourself will now have strongly-typed objects to parse the collections with.</p>

<h3 id="using-codingkeys-to-customize-our-parsing">Using CodingKeys To Customize Our Parsing</h3>

<p>Below is an extreme example, but what if your JSON author decided to use single character key names?  Obviously, you don’t want your data model to have n, s, p and d properties - so you will need to map the poorly named properties into properties that are readable in your code.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">n</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
   "</span><span class="n">s</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
   "</span><span class="n">p</span><span class="s">": 1.50,
   "</span><span class="n">d</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>You can use CodingKeys to fix this.  Consider the following:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"n"</span>
      <span class="k">case</span> <span class="n">sku</span> <span class="o">=</span> <span class="s">"s"</span>
      <span class="k">case</span> <span class="n">price</span> <span class="o">=</span> <span class="s">"p"</span>
      <span class="k">case</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"d"</span>
   <span class="p">}</span>

   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Product</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// Mr Soapy Bar Soap</span></code></pre></figure>

<p>The enum defines the mapping, and the correct CodingKey objects are created that result in your data model being able to use nice names to store the poor names in the JSON.</p>

<h3 id="let-vs-var">let vs var</h3>

<p>You may have noticed that I have declared all the properties in my data models as let.  Given the nature of the code examples, this is intentional.  In all of the cases I have presented so far, we are just reading in the JSON and storing it to access it later.  Without the need for mutability, there is no reason for them to be mutable.  That said, many data models will be initialized with server-side JSON, modified, and then updated via a RESTful back-end API.  Given this, it is probably more common that your data model properties are var.  That said, whenever you have a property that you don’t intend for anyone to modify, you can enforce that by making it let.</p>

<p>Also note, to have a mutable data structure, you need to decode it to a mutable object as well, as shown below.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"n"</span>
      <span class="k">case</span> <span class="n">sku</span> <span class="o">=</span> <span class="s">"s"</span>
      <span class="k">case</span> <span class="n">price</span> <span class="o">=</span> <span class="s">"p"</span>
      <span class="k">case</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"d"</span>
   <span class="p">}</span>

   <span class="k">var</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">n</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
   "</span><span class="n">s</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
   "</span><span class="n">p</span><span class="s">": 1.50,
   "</span><span class="n">d</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">var</span> <span class="nv">product</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Product</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// Mr Soapy Bar Soap</span>
<span class="n">product</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"test"</span>
<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// test</span></code></pre></figure>

<h3 id="parameters-that-might-not-be-there">Parameters That Might Not Be There</h3>

<p>If we consider the JSON we’ve been working with, what happens if the description property is only there sometimes?  For example, what if our playground looks like this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="kd">class</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
   "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
   "</span><span class="n">price</span><span class="s">": 1.50
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Product</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span></code></pre></figure>

<p>This actually generates an error for the key “description” not being found.  We can resolve this in one of two ways:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">var</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span><span class="o">!</span>  <span class="c1">// make it optional</span>
<span class="k">var</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="err">“”</span>  <span class="c1">// provide a default value</span></code></pre></figure>

<p>Which should you use?  The drawbacks of both approaches are clear.  If you need to check for the existence of a property to use later in your code, you probably want to make it an optional.  If you are likely to just be passing that back in further RESTful POST/PUT calls, you can probably just have the default value and avoid the unwrapping.  Even with the extra overhead of unwrapping, I’d likely default to the optional unless I am certain I will never have to check to see if the property has actual data in it.</p>

<h3 id="class-vs-struct">Class vs Struct</h3>

<p>Another big decision you will have to make is whether to make your data model types structs or classes.  Apple suggests that you use value types (struct) instead of reference types when possible.  They provide a rather detailed WWDC talk from 2015 that describes their reasoning for this (<a href="https://developer.apple.com/videos/play/wwdc2015/414/">WWDC Value Types vs Reference Types</a>), which I highly recommend viewing.</p>

<p>One additional factor that will weigh on your decision to create your data models as value types or reference types is your need to interoperate with Objective-C.  You cannot use Swift structs in Objective-C, and this alone may force your hand and cause you to use classes.  Note that if you use either a struct or class, the auto property synthesis will occur unless you overwrite the init(from decoder:).</p>

<h3 id="json-with-nested-array">JSON With Nested Array</h3>

<p>This is all great, but it relies on our JSON being a well known and flat structure.  What if our JSON is more complex?  Consider the following playground:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="kd">struct</span> <span class="kt">ProductCategory</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
      <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
   <span class="p">}</span>
    
   <span class="k">let</span> <span class="nv">categoryName</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">products</span><span class="p">:[</span><span class="kt">Product</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">categoryName</span><span class="s">" : "</span><span class="n">soap</span><span class="s">",
   "</span><span class="n">products</span><span class="s">" : [
         {
            "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
            "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
            "</span><span class="n">price</span><span class="s">": 1.50,
            "</span><span class="n">description</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
         },
         {
            "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Squeeky</span> <span class="kt">Clean</span> <span class="kt">Liquid</span> <span class="kt">Soap</span><span class="s">",
            "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">Squeeky_bottle_1</span><span class="s">",
            "</span><span class="n">price</span><span class="s">": 2.50,
            "</span><span class="n">description</span><span class="s">": "</span><span class="kt">Squeeky</span> <span class="n">clean</span> <span class="k">for</span> <span class="n">pourable</span> <span class="n">freshitude</span><span class="s">"
         }]
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">productCategory</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">ProductCategory</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>

<span class="k">for</span> <span class="n">product</span> <span class="k">in</span> <span class="n">productCategory</span><span class="o">.</span><span class="n">products</span> <span class="p">{</span>
   <span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="p">}</span></code></pre></figure>

<p>So, in this example we have a more complex JSON with an array in it.  This array is an array of dictionary objects.  The way that Codable encourages you to deal with this with a nested data model, as shown above.</p>

<p>That said, you can also separate the two structs like below:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="kd">struct</span> <span class="kt">ProductCategory</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">categoryName</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">products</span><span class="p">:[</span><span class="kt">Product</span><span class="p">]</span>
<span class="p">}</span></code></pre></figure>

<p>Having them nested provides some further context to the reader by associating the inner type with the outer type.  You can see how you would use this outside of Codeable below:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="kd">struct</span> <span class="kt">ProductCategory</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
      <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
   <span class="p">}</span>

   <span class="k">let</span> <span class="nv">categoryName</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">products</span><span class="p">:[</span><span class="kt">Product</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="kt">ProductCategory</span><span class="o">.</span><span class="kt">Product</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"testProduct"</span><span class="p">,</span> <span class="nv">sku</span><span class="p">:</span> <span class="s">"testSku"</span><span class="p">,</span> <span class="nv">price</span><span class="p">:</span> <span class="mf">0.0</span><span class="p">,</span> <span class="nv">description</span><span class="p">:</span> <span class="s">"test"</span><span class="p">);</span>

<span class="k">let</span> <span class="nv">productCategory</span> <span class="o">=</span> <span class="kt">ProductCategory</span><span class="p">(</span><span class="nv">categoryName</span><span class="p">:</span> <span class="s">"testCategory"</span><span class="p">,</span> <span class="nv">products</span><span class="p">:</span> <span class="p">[</span><span class="n">product</span><span class="p">])</span>
<span class="nf">print</span><span class="p">(</span><span class="n">productCategory</span><span class="o">.</span><span class="n">products</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// testProduct</span></code></pre></figure>

<p>Whether this is a readability advantage to you is something you get to decide for yourself.  Just know the option is there.</p>

<h3 id="json-with-nested-dictionary">JSON with Nested Dictionary</h3>

<p>In addition to arrays, it is very common to see dictionaries embedded in dictionaries in JSON.  For example, consider this playground:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="kd">struct</span> <span class="kt">ProductCategory</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
      <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
   <span class="p">}</span>

   <span class="k">let</span> <span class="nv">categoryName</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">product</span><span class="p">:</span><span class="kt">Product</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">categoryName</span><span class="s">" : "</span><span class="n">soap</span><span class="s">",
   "</span><span class="n">product</span><span class="s">" :    {
                  "</span><span class="n">name</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="kt">Bar</span> <span class="kt">Soap</span><span class="s">",
                  "</span><span class="n">sku</span><span class="s">": "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">",
                  "</span><span class="n">price</span><span class="s">": 1.50,
                  "</span><span class="n">description</span><span class="s">": "</span><span class="kt">Mr</span> <span class="kt">Soapy</span> <span class="n">keeps</span> <span class="n">you</span> <span class="n">fresh</span> <span class="n">and</span> <span class="n">clean</span><span class="s">"
                  }
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">productCategory</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">ProductCategory</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">productCategory</span><span class="o">.</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// Mr Soapy Bar Soap</span></code></pre></figure>

<p>In this case, the product category only contains one product and it is a dictionary.  To seamlessly access this through Decodable, we again use a nested type.</p>

<h3 id="problem---heavy-nesting">Problem - Heavy Nesting</h3>

<p>Ideally, you are building your iOS app and your JSON at the same time.  When this is done, it can make sense to have the back-end data model, JSON, and the frontend (iOS, in this case) data model all be the same.  However, this is often not the reality.  The goals of a back-end data model might diverge from the goals of an app’s data model, which can cause you to over-complicate your app’s data model.  For example, consider an API where you place an HTTP GET to return a single specific product (let’s say you pass in the SKU and it returns a product).  What would you want your data model to be like if the API’s data format returned this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="p">{</span>
   <span class="s">"elements"</span><span class="p">:</span> <span class="p">[{</span>
      <span class="s">"element"</span><span class="p">:</span> <span class="p">{</span>
               <span class="s">"name"</span><span class="p">:</span> <span class="s">"Mr Soapy Bar Soap"</span><span class="p">,</span>
               <span class="s">"sku"</span><span class="p">:</span> <span class="s">"MrSoapy_Bar_1"</span><span class="p">,</span>
               <span class="s">"price"</span><span class="p">:</span> <span class="mf">1.50</span><span class="p">,</span>
               <span class="s">"description"</span><span class="p">:</span> <span class="s">"Mr Soapy keeps you fresh and clean"</span>
      <span class="p">}</span>
   <span class="p">}]</span>
<span class="p">}</span></code></pre></figure>

<p>In this case, the API writer has decided to add a lot of flexibility, generality and verbosity (we only wanted one product, but they passed a structure capable of handling not only multiple products but multiple types of data).  While this might be desired to enable dynamic additions to the API’s data format, it will likely result in an inconvenient API for us.  To parse this, your data model might look like this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
   <span class="k">let</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span>
   <span class="k">let</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="kd">struct</span> <span class="kt">ElementData</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">element</span><span class="p">:</span> <span class="kt">Product</span>
<span class="p">}</span>

<span class="kd">struct</span> <span class="kt">Elements</span> <span class="p">:</span> <span class="kt">Codable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elements</span><span class="p">:</span> <span class="p">[</span><span class="kt">ElementData</span><span class="p">]</span>
<span class="p">}</span></code></pre></figure>

<p>Note that ElementData is un-named in the JSON, because elements are an array of objects and not keyed.  Codable is able to deal with this fine.  That said, this created a structure that is going to make little sense in our code.  We can solve this by ignoring other elements of data structure as follows:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">elements</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Elements</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="n">elements</span><span class="o">.</span><span class="n">elements</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">element</span>
<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// Mr Soapy Bar Soap</span></code></pre></figure>

<p>I separated the types instead of nesting them to make sure that instances of Product would be independent.  For this case, this is a fine solution.  However, what happens when you have structures like this all through the JSON?  It is clear there are cases where our data model will be terrible if it mirrors our JSON.</p>

<h3 id="flattening-out-a-json-data-model">Flattening Out A JSON Data Model</h3>

<p>Another approach to such a problem is to manually take over control of our parsing.  Doing this requires us to parse the JSON ourselves, but we can still leverage Codable to make this happen.</p>

<p>To begin with, we are going to be implementing the required init(from decoder:) initializer from Decodable.  This means we will NOT get the auto-synthesis for free, which will change some basics about our data model:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">class</span> <span class="kt">Product</span> <span class="p">:</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span>
   <span class="k">var</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span>
   <span class="k">var</span> <span class="nv">price</span><span class="p">:</span> <span class="kt">Double</span><span class="p">?</span>
   <span class="k">var</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span><span class="p">?</span>
    
   <span class="kd">enum</span> <span class="kt">CodingKeys</span> <span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">elements</span> <span class="o">=</span> <span class="s">"elements"</span>
      <span class="k">case</span> <span class="n">element</span> <span class="o">=</span> <span class="s">"element"</span>
      <span class="k">case</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"name"</span>
      <span class="k">case</span> <span class="n">sku</span> <span class="o">=</span> <span class="s">"sku"</span>
      <span class="k">case</span> <span class="n">price</span> <span class="o">=</span> <span class="s">"price"</span>
      <span class="k">case</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"description"</span>
   <span class="p">}</span>
    
   <span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
      <span class="c1">// TODO</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>First, notice that we are explicitly conforming to Decodable here.  Because we lost the auto-synthesis, we would need to implement Encodable’s required method and I don’t want to complicate this example with that right now.</p>

<p>Second, since we lost auto-synthesis we now need to conform to traditional initialization rules.  I chose to make every variable an optional for this purpose.  The init(from decoder:) initializer will place the parsed data in these variables.</p>

<p>Third, CodingKeys contains all potential keys.  You could nest this structure for additional readability, but for now, I flattened it.</p>

<p>So, given this, let’s take a detailed look at our implementation of the initializer, one line at  a time.  The general strategy is to use <a href="https://developer.apple.com/documentation/swift/decoder">Decoder protocol</a> to dig all the way into the inner part of our JSON, which we will then extract and initialize our object with.  Note that this code is making the assumption that we always know we only have a single product in the JSON.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elementsContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
<span class="p">}</span></code></pre></figure>

<p>We start out by using the container(keyedBy:) method on the Decoder protocol to get a KeyedDecodingContainer.  We use a try before calling this to propagate any possible error up to the caller to deal with, since we can never be guaranteed that our JSON will be valid and have the values we expect.  In this case, we are using a KeyedDecodingContainer because the root dictionary has one element in it with a key of “elements”.  There are three types of containers:</p>

<ol>
  <li><strong>KeyedDecodingContainer</strong> - the data of keyed containers like a dictionary.</li>
  <li><strong>SingleValueDecodingContainer</strong> - the data of a container that holds a single primitive.</li>
  <li><strong>UnkeyedDecodingContainer</strong> - the data of a container with no keys, such as an array.</li>
</ol>

<p>Our next step is to get the array of elements:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elementsContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
        
   <span class="k">var</span> <span class="nv">elementsArrayContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsContainer</span><span class="o">.</span><span class="nf">nestedUnkeyedContainer</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">elements</span><span class="p">)</span>
        
   <span class="k">if</span> <span class="p">(</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">count</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">elementsArrayContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"elements must be an array with one item"</span><span class="p">)</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>This code gets an <strong>unkeyed</strong> container.  The value of elements in our dictionary is an array of objects, so we can enumerate those with an unkeyed container.  However, before we do that enumeration, we check to be sure that we have exactly one object in the array, else we throw an error.  When digging into a container, there are four methods you will use:</p>

<p>For a <strong>KeyedDecodingContainer</strong> (<a href="https://developer.apple.com/documentation/swift/keyeddecodingcontainerprotocol">Apple documentation</a>):</p>

<p>nestedContainer(keyedBy: forKey:) - used when you have the key for the value the container is stored in and the value is keyed container like a dictionary.</p>

<p>nestedUnkeyedContainer(forKey:) - used when you have the key for the value the container is stored in and the value is not keyed, like an array.</p>

<p>For an <strong>UnkeyedDecodingContainer</strong> (<a href="https://developer.apple.com/documentation/swift/unkeyeddecodingcontainer">Apple documentation</a>)</p>

<p>nestedContainer(keyedBy:) - used when you want the next container in the current unkeyed container and that container is keyed like a dictionary.</p>

<p>nestedUnkeyedContainer() - used to get the next container in the current unkeyed container, when that container is not keyed, like an array.</p>

<p>UnkeyedDecodingContainers allow you to iterate them.  Each time you call nestedContainer(keyedBy:) or nestedUnkeyedContainer(), the container increments itself to the next item it stores.  This kind of incrementation can also occur if you are simply decoding values.  Because they iterate like this, they mutate, so we need to store them as var.</p>

<p>Also note that the version of the DecodingError’s dataCorruptedError method we use is the one for an unkeyed container, because elementsArrayContainer is unkeyed.  The compiler will error in a confusing way if you try to use the wrong format.</p>

<p>Thus, the next step in our parser is to iterate the array:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elementsContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
        
   <span class="k">var</span> <span class="nv">elementsArrayContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsContainer</span><span class="o">.</span><span class="nf">nestedUnkeyedContainer</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">elements</span><span class="p">)</span>
        
   <span class="k">if</span> <span class="p">(</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">count</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">elementsArrayContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"elements must be an array with one item"</span><span class="p">)</span>
   <span class="p">}</span>
        
   <span class="k">while</span> <span class="o">!</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">isAtEnd</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">elementDictionaryWrapperContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsArrayContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>We use a while loop that checks the condition that the elementsArrayContainer is not at the end.  In our JSON, the array contains a single dictionary.  Based on this, we know we need to get a keyed container for the dictionary, which is elementDictionaryWrappedContainer.  Getting this dictionary also increments our array to the next element, which will cause the while loop to exit since there is only one.  The result is a new KeyedDecodingContainer.  For this one, we need to get the dictionary in the value named with the element key:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elementsContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
        
   <span class="k">var</span> <span class="nv">elementsArrayContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsContainer</span><span class="o">.</span><span class="nf">nestedUnkeyedContainer</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">elements</span><span class="p">)</span>
        
   <span class="k">if</span> <span class="p">(</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">count</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">elementsArrayContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"elements must be an array with one item"</span><span class="p">)</span>
   <span class="p">}</span>
        
   <span class="k">while</span> <span class="o">!</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">isAtEnd</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">elementDictionaryWrapperContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsArrayContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
		
      <span class="k">let</span> <span class="nv">elementContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementDictionaryWrapperContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">element</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Simple enough.  This is another KeyedDecodingContainer, and we request the one with the element CodingKey.  Now we have elementContainer, which includes the values we want to initialize this object with.  Putting it all together:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">elementsContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
        
   <span class="k">var</span> <span class="nv">elementsArrayContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsContainer</span><span class="o">.</span><span class="nf">nestedUnkeyedContainer</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">elements</span><span class="p">)</span>
        
   <span class="k">if</span> <span class="p">(</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">count</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">elementsArrayContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"elements must be an array with one item"</span><span class="p">)</span>
   <span class="p">}</span>
        
   <span class="k">while</span> <span class="o">!</span><span class="n">elementsArrayContainer</span><span class="o">.</span><span class="n">isAtEnd</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">elementDictionaryWrapperContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementsArrayContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
		
      <span class="k">let</span> <span class="nv">elementContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementDictionaryWrapperContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">element</span><span class="p">)</span>
		
      <span class="k">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">String</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">name</span><span class="p">)</span>
      <span class="k">self</span><span class="o">.</span><span class="n">sku</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">String</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">sku</span><span class="p">)</span>
      <span class="k">self</span><span class="o">.</span><span class="n">price</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Double</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">price</span><span class="p">)</span>
      <span class="k">self</span><span class="o">.</span><span class="n">description</span> <span class="o">=</span> <span class="k">try</span> <span class="n">elementContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">String</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">description</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Again, note that every call into the decoding containers uses a try to propagate errors up to the caller.  The decodes are simple, because they are now our foundational types.  As for the code that uses our init, it only changes a little:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">product</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Product</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">name</span><span class="o">!</span><span class="p">)</span>
<span class="c1">// Mr Soapy Bar Soap</span></code></pre></figure>

<p>The product is decoded directly from the full JSON that we pass in.  This makes sense, because we are using Product.self as our data model type, instead of Elements.self from our last example.  The data models for Elements and Element are completely avoided.  Notice the use of try!.  Since this is a playground, it is OK to crash if our parsing throws an error.  In reality, we would handle an error like this more elegantly.  Likewise, we use the crash operator to unwrap the optional when printing the name product.</p>

<p>All of this begs the question, should I do this?  That depends on what you value in an architecture.  I believe the fundamental problem is in the JSON format.  It is making the current call more complicated to solve problems that do not yet exist.  This is generally bad practice.  That said, if you go down a custom road to clean up your data models, you will face the work on decoding (and encoding!) your data model to a sensible format.  When the “cruft” brings no value, such as in the example above, I’m happy to spend the extra resource to clean it up in my codebase.</p>

<h3 id="an-inconvenient-json---custom-parsing">An Inconvenient JSON - Custom Parsing</h3>

<p>I would argue that JSON works best when it is a simple document of well-defined key/value types.  As you can see from the above examples, we really need to understand what we are looking for in order to parse it.  Unfortunately, this isn’t always the case either.</p>

<p>Consider the following JSON showing pickup times for a set of SKUs in a store:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">skus</span><span class="s">": {
      "</span><span class="n">storePickup</span><span class="s">": {
         "</span><span class="kt">MrSoapy_Bar_1</span><span class="s">": {
            "</span><span class="n">pickupTimes</span><span class="s">": {
               "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">09</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">": {},
               "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">10</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">": {}
            }
         },
         "</span><span class="kt">Squeeky_bottle_1</span><span class="s">": {
            "</span><span class="n">pickupTimes</span><span class="s">": {
               "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">09</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">": {},
               "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">10</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">": {}
            }
         }
      }
   }
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>Assume this JSON was returned by a RESTful API where we asked for store pickup times for various SKUs.  There are two uncommon things about this JSON:</p>

<p>First, the value of the “storePickup” element looks like an array, but it is really a dictionary of objects keyed by a sku value that we don’t know ahead of time.  We will have to find a way to dynamically parse those.</p>

<p>We will assume that the API that returned this JSON is ONLY returning storePickup SKUs, so that part of the JSON is not dynamic and we can parse it directly.</p>

<p>The second oddity is with “pickupTimes.”  The “pickupTimes” are stored in a dictionary in the same way as the skus in the “storePickup” key’s value, and their values are also keys with data in them.  The values are empty dictionaries for expandability while the keys are dates.  Yikes!</p>

<p>So, we need to start by considering what our data model should look like.  I’m proposing this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">StoreSkus</span> <span class="p">:</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">pickupSkus</span><span class="p">:</span> <span class="p">[</span><span class="kt">StorePickupSkus</span><span class="p">]</span>
    
   <span class="kd">struct</span> <span class="kt">StorePickupSkus</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span>
      <span class="k">let</span> <span class="nv">pickupTimes</span><span class="p">:</span> <span class="p">[</span><span class="kt">Date</span><span class="p">]</span>
        
      <span class="nf">init</span><span class="p">(</span><span class="nv">sku</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">pickupTimes</span><span class="p">:</span> <span class="p">[</span><span class="kt">Date</span><span class="p">])</span> <span class="p">{</span>
         <span class="k">self</span><span class="o">.</span><span class="n">sku</span> <span class="o">=</span> <span class="n">sku</span>
         <span class="k">self</span><span class="o">.</span><span class="n">pickupTimes</span> <span class="o">=</span> <span class="n">pickupTimes</span>
      <span class="p">}</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>So, the main data structure will be StoreSkus, and it will have a property that is an array of StorePickupSkus.  This struct conforms to Codable.  The inner struct is StorePickupSkus.  It contains a String for the sku and an array of Date objects to represent the available pickup times.  It also contains an init method.  Since the properties are not optionals, the init is required.  Also, note that we aren’t implementing Decodable in this struct.  Given that we are doing manual JSON parsing and our data structure can’t match the JSON, it is easiest to do it all in one place since it is small.</p>

<p>Like with the last example, let’s see what our init(from decoder:) looks like, step by step.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">pickupSkus</span><span class="p">:[</span><span class="kt">StorePickupSkus</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        
   <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="k">let</span> <span class="nv">skusContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">skus</span><span class="p">)</span>

   <span class="k">self</span><span class="o">.</span><span class="n">pickupSkus</span> <span class="o">=</span> <span class="n">pickupSkus</span>
<span class="p">}</span></code></pre></figure>

<p>We start out by creating a mutable version of an array of StorePickupSkus.  We will be building this up as we parse the JSON.  Since this is an initializer, we have to be sure to initialize the property at the end of the initializer with this value we are building up.  Secondly, we need to get the main container.  This is straightforward and we’ve done it before.  Finally, we are going to get a nested container for dictionary contained in the value for the “skus” key.  We also need to add coding keys to the StoreSkus struct, as follows:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">StoreSkus</span> <span class="p">:</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">skus</span>
      <span class="k">case</span> <span class="n">storePickup</span>
      <span class="k">case</span> <span class="n">pickupTimes</span>
   <span class="p">}</span>
	
   <span class="c1">// ...</span>
<span class="p">}</span></code></pre></figure>

<p>Notice that I left off the “= <someString>” part of the keys.  As it turns out, if your string matches the case in the enum, defining the string is not necessary.</someString></p>

<p>Recall when we first looked at the CodingKey protocol how the compiler generates key objects for you based on the “CodingKeys” enum that conforms to CodingKey.  As it turns out, if you need to manipulate the keys themselves, you need to implement a custom CodingKey type:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">CustomCodingKey</span><span class="p">:</span> <span class="kt">CodingKey</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">intValue</span><span class="p">:</span> <span class="kt">Int</span><span class="p">?</span>
        
   <span class="nf">init</span><span class="p">?(</span><span class="nv">intValue</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">self</span><span class="o">.</span><span class="n">intValue</span> <span class="o">=</span> <span class="n">intValue</span>
      <span class="k">self</span><span class="o">.</span><span class="n">stringValue</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(</span><span class="n">intValue</span><span class="p">)</span>
   <span class="p">}</span>
        
   <span class="k">var</span> <span class="nv">stringValue</span><span class="p">:</span> <span class="kt">String</span>
        
   <span class="nf">init</span><span class="p">?(</span><span class="nv">stringValue</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">self</span><span class="o">.</span><span class="n">stringValue</span> <span class="o">=</span> <span class="n">stringValue</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>This implementation is very simple.  In our case, we need to get named keys from our container, so we are really only concerned with the Int parts of the interface to conform to the protocol.  For the Strings, when a CustomCodingKey is created, we will save the String value so we can access it later.  All that’s left to do is to decode the container with the CustomCodingKey.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">pickupSkus</span><span class="p">:[</span><span class="kt">StorePickupSkus</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        
   <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="k">let</span> <span class="nv">skusContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">skus</span><span class="p">)</span>
	
   <span class="k">let</span> <span class="nv">storePickupContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skusContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">storePickup</span><span class="p">)</span>
   <span class="k">for</span> <span class="n">skuKey</span> <span class="k">in</span> <span class="n">storePickupContainer</span><span class="o">.</span><span class="n">allKeys</span> <span class="p">{</span>
      <span class="nf">print</span><span class="p">(</span><span class="n">skuKey</span><span class="p">)</span>
   <span class="p">}</span>
	
   <span class="k">self</span><span class="o">.</span><span class="n">pickupSkus</span> <span class="o">=</span> <span class="n">pickupSkus</span>
<span class="p">}</span>
<span class="c1">// CustomCodingKey(stringValue: "Squeeky_bottle_1", intValue: nil)</span>
<span class="c1">// CustomCodingKey(stringValue: "MrSoapy_Bar_1", intValue: nil)</span></code></pre></figure>

<p>We create storePickupContainer.  In the sample JSON, the “storePickup” key has a dictionary with two keys in it.  Those keys are named for the sku their value’s describe (also as dictionaries).  The nestedContainer(keyedBy type:, forKey key:) method takes two parameters.  The type is the key type to use with the container, which is our custom type (remember, CustomCodingKey.self is like calling the class method in Objective-C).  The key is the actual key the container is associated with, which is an instance of an object that conforms to CodingKey that references the “storePickup” String like in the JSON (phew!).</p>

<p>To iterate this, the container has an allKeys accessor we can use to get an array of our CustomCodingKey instances.  If you run the decoder:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">pickupSkus</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">StoreSkus</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span></code></pre></figure>

<p>….you should see print output the two instances of CustomCodingKey.</p>

<p>The next step is to get the nested container which are named with the skus themselves.  Because we have objects in our JSON that are keyed by a non-dyanmic string “pickupTimes”, we can use the CodingKeys to get at the container we want.  Within that container, we have a list of dates stored as key names.  We need to get those dates for our data model.  This works just like the example above, and we can reuse the CustomCodingKey struct.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">pickupSkus</span><span class="p">:[</span><span class="kt">StorePickupSkus</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        
   <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="k">let</span> <span class="nv">skusContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">skus</span><span class="p">)</span>

   <span class="k">let</span> <span class="nv">pickupTimesContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skuContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">pickupTimes</span><span class="p">)</span>
<span class="p">}</span></code></pre></figure>

<p>It is worth noting that we have a second option to accomplish this.  Consider the following code:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">skuContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">storePickupContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="n">skuKey</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">pickupTimesContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skuContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="p">(</span><span class="nv">stringValue</span><span class="p">:</span><span class="s">"pickupTimes"</span><span class="p">)</span><span class="o">!</span><span class="p">)</span></code></pre></figure>

<p>In this case, when we retrieve the skuContainer, we use the CustomCodingKey type.  That means in order to get the pickupTimesContainer, we have to create an instance of CustomCodeKey initialized with the “pickupTimes” String we want to use as the key.  This works as well.  The type of custom key used to create the container is the type of key the system expects you to use to build the next container.  My preference is to use the first example for simplicity, especially when you consider we probably shouldn’t force unwrap the CustomCodingKey initialization, which gives us extra error stuff to handle.</p>

<p>For the next step, we are going to create an empty mutable array of Date objects.  Eventually, this will store the dates we parse from the JSON.  For now, it is a placeholder.  This iteration uses the allKeys accessor on the pickupTimesContainer, just like we saw above.  If you print the key, you can see the code is iterating through both pairs of objects.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">pickupSkus</span><span class="p">:[</span><span class="kt">StorePickupSkus</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        
   <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="k">let</span> <span class="nv">skusContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">skus</span><span class="p">)</span>
	
   <span class="k">let</span> <span class="nv">pickupTimesContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skuContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">pickupTimes</span><span class="p">)</span>
	
   <span class="k">var</span> <span class="nv">pickupTimes</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

   <span class="k">for</span> <span class="n">pickupTimeKey</span> <span class="k">in</span> <span class="n">pickupTimesContainer</span><span class="o">.</span><span class="n">allKeys</span> <span class="p">{</span>
      <span class="nf">print</span><span class="p">(</span><span class="n">pickupTimeKey</span><span class="p">)</span>
   <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// CustomCodingKey(stringValue: "2019-12-09T07:00:00.000-0800", intValue: nil)</span>
<span class="c1">// CustomCodingKey(stringValue: "2019-12-10T07:00:00.000-0800", intValue: nil)</span>
<span class="c1">// CustomCodingKey(stringValue: "2019-12-09T07:00:00.000-0800", intValue: nil)</span>
<span class="c1">// CustomCodingKey(stringValue: "2019-12-10T07:00:00.000-0800", intValue: nil)</span></code></pre></figure>

<p>Next, we want to use DateFormatter to convert the date string into a Date object.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">var</span> <span class="nv">pickupTimes</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">pickupTimeKey</span> <span class="k">in</span> <span class="n">pickupTimesContainer</span><span class="o">.</span><span class="n">allKeys</span> <span class="p">{</span>
   <span class="k">let</span> <span class="nv">dateFormatter</span> <span class="o">=</span> <span class="kt">DateFormatter</span><span class="p">()</span>
   <span class="n">dateFormatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">Locale</span><span class="p">(</span><span class="nv">identifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
   <span class="n">dateFormatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"</span>
   <span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="n">dateFormatter</span><span class="o">.</span><span class="nf">date</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">pickupTimeKey</span><span class="o">.</span><span class="n">stringValue</span><span class="p">)</span>
	
   <span class="k">if</span> <span class="p">(</span><span class="n">date</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">pickupTimes</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">date</span><span class="o">!</span><span class="p">)</span>  
   <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="n">pickupTimeKey</span><span class="p">,</span> <span class="nv">in</span><span class="p">:</span> <span class="n">pickupTimesContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"Invalid date format"</span><span class="p">)</span>
   <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>We simply use an instance of DateFormatter to convert the String into a Date object.  To pass the date String to the date formatter, we use the stringValue accessor on the pickupTimeKey instance of CustomCodingKey to access the String part of the key.  This gives us a Date optional, which we either add to the mutable array, or we throw an error if the format is not what we expect.  When we create the DecodingError, we are using a format of the dataCorruptedError method that works with a keyed collection.</p>

<p>Finally, we have the data we need to construct our StorePickupSkus object:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">storePickupSku</span> <span class="o">=</span> <span class="kt">StorePickupSkus</span><span class="p">(</span><span class="nv">sku</span><span class="p">:</span> <span class="n">skuKey</span><span class="o">.</span><span class="n">stringValue</span><span class="p">,</span> <span class="nv">pickupTimes</span><span class="p">:</span> <span class="n">pickupTimes</span><span class="p">)</span>
<span class="n">pickupSkus</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">storePickupSku</span><span class="p">)</span></code></pre></figure>

<p>Again, we use the stringValue accessor on our CustomCodingKey class to access the key’s String object and initialize using our custom initializer.  We then add this object to the pickupSkus mutable array we added to the top of the method.</p>

<p>Putting it all together, we end up with an initializer that looks like this:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
   <span class="k">var</span> <span class="nv">pickupSkus</span><span class="p">:[</span><span class="kt">StorePickupSkus</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

   <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
   <span class="k">let</span> <span class="nv">skusContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">skus</span><span class="p">)</span>

   <span class="k">let</span> <span class="nv">storePickupContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skusContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">storePickup</span><span class="p">)</span>

   <span class="k">for</span> <span class="n">skuKey</span> <span class="k">in</span> <span class="n">storePickupContainer</span><span class="o">.</span><span class="n">allKeys</span> <span class="p">{</span>
      <span class="k">let</span> <span class="nv">skuContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">storePickupContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="n">skuKey</span><span class="p">)</span>

      <span class="k">let</span> <span class="nv">pickupTimesContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">skuContainer</span><span class="o">.</span><span class="nf">nestedContainer</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CustomCodingKey</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">pickupTimes</span><span class="p">)</span>

      <span class="k">var</span> <span class="nv">pickupTimes</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

      <span class="k">for</span> <span class="n">pickupTimeKey</span> <span class="k">in</span> <span class="n">pickupTimesContainer</span><span class="o">.</span><span class="n">allKeys</span> <span class="p">{</span>
         <span class="k">let</span> <span class="nv">dateFormatter</span> <span class="o">=</span> <span class="kt">DateFormatter</span><span class="p">()</span>
         <span class="n">dateFormatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">Locale</span><span class="p">(</span><span class="nv">identifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
         <span class="n">dateFormatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"</span>
         <span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="n">dateFormatter</span><span class="o">.</span><span class="nf">date</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">pickupTimeKey</span><span class="o">.</span><span class="n">stringValue</span><span class="p">)</span>
         <span class="k">if</span> <span class="p">(</span><span class="n">date</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">pickupTimes</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">date</span><span class="o">!</span><span class="p">)</span>
         <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="c1">// Throw error</span>
            <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="n">pickupTimeKey</span><span class="p">,</span> <span class="nv">in</span><span class="p">:</span> <span class="n">pickupTimesContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"Invalid date format"</span><span class="p">)</span>
         <span class="p">}</span>
      <span class="p">}</span>

      <span class="k">let</span> <span class="nv">storePickupSku</span> <span class="o">=</span> <span class="kt">StorePickupSkus</span><span class="p">(</span><span class="nv">sku</span><span class="p">:</span> <span class="n">skuKey</span><span class="o">.</span><span class="n">stringValue</span><span class="p">,</span> <span class="nv">pickupTimes</span><span class="p">:</span> <span class="n">pickupTimes</span><span class="p">)</span>
      <span class="n">pickupSkus</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">storePickupSku</span><span class="p">)</span>
   <span class="p">}</span>

   <span class="k">self</span><span class="o">.</span><span class="n">pickupSkus</span> <span class="o">=</span> <span class="n">pickupSkus</span>
<span class="p">}</span></code></pre></figure>

<p>If we print the output of the instance of pickupSkus we created, we can see this works.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">pickupSkus</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">StoreSkus</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">pickupSkus</span><span class="p">)</span>
<span class="c1">// StoreSkus(pickupSkus: [__lldb_expr_3.StoreSkus.StorePickupSkus(sku: "MrSoapy_Bar_1", pickupTimes: [2019-12-09 15:00:00 +0000, 2019-12-10 15:00:00 +0000]), __lldb_expr_3.StoreSkus.StorePickupSkus(sku: "Squeeky_bottle_1", pickupTimes: [2019-12-09 15:00:00 +0000, 2019-12-10 15:00:00 +0000])])</span></code></pre></figure>

<p>Should you have to do stuff like this?  Hopefully not.  The example presented here is overly complicated with the intent of providing future flexibility.  While understandable why an API writer might want such flexibility, strongly typed languages such as Swift really make it a bad idea.  The data format belonging to your API should be treated as a contract much like your API.  Some dynamism can make things easier for both your clients and your back-end, but it is easy to go too far.  JSON works best as key-value pairs, and your dynamism should respect this to avoid the extra theatrics shown here.</p>

<h3 id="parsing-an-unkeyed-array-of-dates">Parsing an Unkeyed Array of Dates</h3>

<p>Extending a prior concept, consider this simple JSON that contains a list of date strings:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">jsonData</span> <span class="o">=</span> <span class="s">"""
{
   "</span><span class="n">dates</span><span class="s">": [
      "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">09</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">",
      "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">10</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">",
      "</span><span class="mi">2019</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">11</span><span class="kt">T07</span><span class="p">:</span><span class="mo">00</span><span class="p">:</span><span class="mf">00.000</span><span class="o">-</span><span class="mi">0800</span><span class="s">"
      ]
}
"""</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span></code></pre></figure>

<p>We can parse this manually with an unkeyed container.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">DateList</span> <span class="p">:</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">dates</span>
   <span class="p">}</span>
    
   <span class="k">var</span> <span class="nv">dates</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span>
    
   <span class="nf">init</span><span class="p">(</span><span class="n">from</span> <span class="nv">decoder</span><span class="p">:</span> <span class="kt">Decoder</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
      <span class="k">var</span> <span class="nv">dates</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        
      <span class="k">let</span> <span class="nv">container</span> <span class="o">=</span> <span class="k">try</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">container</span><span class="p">(</span><span class="nv">keyedBy</span><span class="p">:</span> <span class="kt">CodingKeys</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
      <span class="k">var</span> <span class="nv">datesContainer</span> <span class="o">=</span> <span class="k">try</span> <span class="n">container</span><span class="o">.</span><span class="nf">nestedUnkeyedContainer</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="o">.</span><span class="n">dates</span><span class="p">)</span>
        
      <span class="k">while</span> <span class="o">!</span><span class="n">datesContainer</span><span class="o">.</span><span class="n">isAtEnd</span> <span class="p">{</span>
         <span class="k">let</span> <span class="nv">dateFormatter</span> <span class="o">=</span> <span class="kt">DateFormatter</span><span class="p">()</span>
         <span class="n">dateFormatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">Locale</span><span class="p">(</span><span class="nv">identifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
         <span class="n">dateFormatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"</span>
         <span class="k">let</span> <span class="nv">dateString</span> <span class="o">=</span> <span class="k">try</span> <span class="n">datesContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">String</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
         <span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="n">dateFormatter</span><span class="o">.</span><span class="nf">date</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">dateString</span><span class="p">)</span>
         <span class="k">if</span> <span class="p">(</span><span class="n">date</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dates</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">date</span><span class="o">!</span><span class="p">)</span>
         <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="c1">// Throw error</span>
            <span class="k">throw</span> <span class="kt">DecodingError</span><span class="o">.</span><span class="nf">dataCorruptedError</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">datesContainer</span><span class="p">,</span> <span class="nv">debugDescription</span><span class="p">:</span> <span class="s">"Invalid date format"</span><span class="p">)</span>
         <span class="p">}</span>
      <span class="p">}</span>
        
      <span class="k">self</span><span class="o">.</span><span class="n">dates</span> <span class="o">=</span> <span class="n">dates</span>
   <span class="p">}</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">dates</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">DateList</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">dates</span><span class="p">)</span>
<span class="c1">// DateList(dates: [2019-12-09 15:00:00 +0000, 2019-12-10 15:00:00 +0000, 2019-12-11 15:00:00 +0000])</span></code></pre></figure>

<p>This is nothing we haven’t seen before, it is just presented slightly differently.  The array doesn’t contain other dictionaries, it contains the data directly.  We use an unkeyed container to iterate over these values.  To pull the data in the current item we are iteration, we simply decode it:</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="k">let</span> <span class="nv">dateString</span> <span class="o">=</span> <span class="k">try</span> <span class="n">datesContainer</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">String</span><span class="o">.</span><span class="k">self</span><span class="p">)</span></code></pre></figure>

<p>This can result in an error, so we use a try so the error gets passed up to the caller.  The rest is just building the Date object via a DataFormatter, adding it to a mutable Date array and assigning it to the member property.</p>

<p>That said, we can actually accomplish this much easier and automatically.</p>

<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span class="kd">struct</span> <span class="kt">DateList</span> <span class="p">:</span> <span class="kt">Decodable</span> <span class="p">{</span>
   <span class="kd">enum</span> <span class="kt">CodingKeys</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="kt">CodingKey</span> <span class="p">{</span>
      <span class="k">case</span> <span class="n">dates</span>
   <span class="p">}</span>
    
   <span class="k">var</span> <span class="nv">dates</span><span class="p">:[</span><span class="kt">Date</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>

<span class="k">let</span> <span class="nv">dateFormatter</span> <span class="o">=</span> <span class="kt">DateFormatter</span><span class="p">()</span>
<span class="n">dateFormatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">Locale</span><span class="p">(</span><span class="nv">identifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
<span class="n">dateFormatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"</span>

<span class="n">decoder</span><span class="o">.</span><span class="n">dateDecodingStrategy</span> <span class="o">=</span> <span class="o">.</span><span class="nf">formatted</span><span class="p">(</span><span class="n">dateFormatter</span><span class="p">)</span>

<span class="k">let</span> <span class="nv">dates</span> <span class="o">=</span> <span class="k">try!</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">DateList</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">jsonData</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">dates</span><span class="p">)</span>
<span class="c1">// DateList(dates: [2019-12-09 15:00:00 +0000, 2019-12-10 15:00:00 +0000, 2019-12-11 15:00:00 +0000])</span></code></pre></figure>

<p>Because we are using the same date decoding strategy throughout the JSON, we do not need to customize our JSON parsing.  We can set the dateDecodingStrategy in the JSONDecoder to use our DateFormatter, and get rid of the initialization method and the custom parsing.  DateDecodingStrategy provides secondsSince1970, millsecondsSince1970 and ios8601 formats by default.  If you are using those, you don’t even need a custom DateFormatter.</p>

<h3 id="summary">Summary</h3>

<p>We’ve covered much ground and several examples that should show you how to piece together various techniques to parse most kinds of JSON into data models.  There are a myriad of strategies you can use to parse JSON in Swift I haven’t shown here.  Most of the difficulty will result from how difficult the JSON you have is to deal with.   I encourage you to work with your API writers on JSON standards that are easy to deal with AND reflect what your data model should look like.</p>]]></content><author><name>Wade Weitzel</name></author><category term="swift" /><category term="swift" /><category term="json" /><category term="decodable" /><summary type="html"><![CDATA[A deep dive into the Decoder protocol…]]></summary></entry></feed>