<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kenny Dubroff (froggomad)</title>
    <description>The latest articles on DEV Community by Kenny Dubroff (froggomad) (@froggomad).</description>
    <link>https://dev.to/froggomad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F472993%2Fe78fa10a-5d2a-4c18-91ee-3b6f03136b90.jpeg</url>
      <title>DEV Community: Kenny Dubroff (froggomad)</title>
      <link>https://dev.to/froggomad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/froggomad"/>
    <language>en</language>
    <item>
      <title>Why is ChatGPT talking to itself?</title>
      <dc:creator>Kenny Dubroff (froggomad)</dc:creator>
      <pubDate>Sat, 27 May 2023 21:43:20 +0000</pubDate>
      <link>https://dev.to/froggomad/why-is-chatgpt-talking-to-itself-3i7o</link>
      <guid>https://dev.to/froggomad/why-is-chatgpt-talking-to-itself-3i7o</guid>
      <description>&lt;h3&gt;
  
  
  Human Language as a Programming Language
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0gHx-bDN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2048/0%2ASbHPxbfDHIbVa1Pl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0gHx-bDN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2048/0%2ASbHPxbfDHIbVa1Pl.png" alt="Generated with Midjourney — **3 AI chat bots having a conversation — v 5.1 — q 2**" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today we’re going to take a break from programming (sort-of) and discuss a unique take on improving ChatGPT’s problem solving abilities.&lt;/p&gt;

&lt;p&gt;I’ve recently been leveraging AI to create children’s coloring books. I have zero artistic creativity, but so far I’ve been able to publish several and with each iteration I explore new ways to automate the process. I’m to the point now where I can create around a 120–200 page coloring book in less than an hour. But I have a problem…&lt;/p&gt;

&lt;h3&gt;
  
  
  I’m not making any sales
&lt;/h3&gt;

&lt;p&gt;I’m not really surprised since my focus has been entirely on generating “passable” content in the quickest way possible. I have some focus on quality as well beyond passing the publisher’s quality checks, but I digress. So far I’ve made $0.13 in royalties and I’d like to start improving that. So I thought I’d leverage AI more and start getting ChatGPT to write my titles, marketing descriptions, and choose keywords. “Default” ChatGPT does well enough at this, excelling at creativity, but without direction, the results won’t be great… and could even get you slapped with a takedown order or lawsuit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prediction Engine
&lt;/h3&gt;

&lt;p&gt;When I first started using ChatGPT, I approached it as if it were a search engine and this produced far better results than using a search engine. I remember telling everyone I came across that it was amazing — it was like “having a conversation with Google”. But I soon started running into the common problems we have with large language models in the form of “hallucinations” (the model tells you a wrong answer with 100% confidence that it’s truthful and accurate).&lt;/p&gt;

&lt;p&gt;Since it’s a prediction model, if you don’t “shape” it, it will sort-of blindly predict what comes next and may give you more misleading information than if you give it a specific role. It’s not trying to do that at all, and there are safeguards in place to prevent things like that from happening, but in my experience, it needs a lot of help from me in pointing out mistakes and errors. This is not only time-consuming, but eats away at my (currently limited) number of messages I can exchange with GPT-4 (the latest ChatGPT model).&lt;/p&gt;

&lt;h3&gt;
  
  
  My First Attempt at a Good Title May Have Resulted in a Lawsuit 👮
&lt;/h3&gt;

&lt;p&gt;My latest coloring book features princesses in various situations. I know ChatGPT does better with more information, so I gave it a general purpose and fed it a bunch of my prompts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s-ycDgmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AGEGFZDonuhvWGamF5CzLFA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s-ycDgmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AGEGFZDonuhvWGamF5CzLFA.png" alt="" width="581" height="777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2qsjoukT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AyOgyywFozDTEEV-pqNVnWg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2qsjoukT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AyOgyywFozDTEEV-pqNVnWg.png" alt="" width="523" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did ChatGPT just say the “D” word? In my title? That I’m commercializing… yeah pretty sure that’s not ok… and Barbiecore seems a little dicey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GjGRQOug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aqe6Vjf3Bx3ifq6q5o8zuxQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GjGRQOug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aqe6Vjf3Bx3ifq6q5o8zuxQ.png" alt="" width="525" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, let’s break that interaction down in reverse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;ChatGPT is aware of the legal consequences of using another entity’s trademark&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ChatGPT is aware that Disney is trademarked&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ChatGPT is aware I want to generate revenue&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ChatGPT advised me to use Disney&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While #4 isn’t strictly a hallucination because I didn’t ask “not to get sued”, ChatGPT generally attempts to look out for a user’s well-being and provides disclaimers when it notices something in its advice may be harmful to the user.&lt;/p&gt;

&lt;p&gt;Further, I asked about the use of “BarbieCore” and ChatGPT admitted this is a gray area since Mattel doesn’t hold a trademark over “BarbieCore” and it is a widely-used term, but it could bring legal consequences anyway.&lt;/p&gt;

&lt;p&gt;So what can we do to reduce hallucinations such as this?&lt;/p&gt;

&lt;h3&gt;
  
  
  Human Language as a Programming Language
&lt;/h3&gt;

&lt;p&gt;A lot of software developers are afraid of losing their jobs to AI right now, but I think we’re probably in one of the best positions to be in for a number of reasons that I’ll maybe explore in another post. In this one, I’ll focus on the one that makes the most logical sense to me — using my words as a tool to shape and manipulate a software application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Role-Playing with AI
&lt;/h3&gt;

&lt;p&gt;One of the most effective strategies I’ve found for shaping and manipulating AI chat bots, particularly ChatGPT, is role-playing. This involves simulating a conversation between different roles, each with their own unique perspective and objectives. For example, in my coloring book project, I simulated a conversation between a kindergarten teacher, a marketing professional, a business professional, and a legal professional.&lt;/p&gt;

&lt;p&gt;The kindergarten teacher’s role was to focus on the well-being of children, suggesting ideas that would be exciting and engaging for them. The marketing professional’s role was to focus on revenue generation, emphasizing the need to appeal to parents who would be making the purchase. The business professional kept the conversation focused on the topic of generating revenue, and the legal professional ensured all suggestions were legally sound.&lt;/p&gt;

&lt;p&gt;This role-play approach led to a more comprehensive and balanced discussion. It allowed the AI to consider a wider range of perspectives and generate solutions that were more comprehensive and balanced. It also made the conversation more engaging and relatable, as I could see my own concerns and objectives reflected in the different roles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Establishing a Baseline
&lt;/h3&gt;

&lt;p&gt;I don’t know the inner-workings of ChatGPT, but I know when I design chat bots using large language models, I direct them with a role and formatting instructions to begin with and I ensure this message is carried forward in every conversation had with the bot so it’s always directed. I also carry the user’s first message forward, or first few messages depending on token usage. This ensures that the bot is directed by me for use in my application as I intend and also meets the user’s goals.&lt;/p&gt;

&lt;p&gt;I assume ChatGPT is the same, and maybe they’ve built some “forgetting” into their “memory”. My best bet actually probably would’ve been to start a new conversation, but this worked this time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YA8OEauM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AJ6j8ahGO5l-mdtHs7ZGd3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YA8OEauM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AJ6j8ahGO5l-mdtHs7ZGd3w.png" alt="" width="548" height="906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s a lot going on here, so let’s break that down:&lt;/p&gt;

&lt;p&gt;I reset the conversation by asking ChatGPT to forget all prior messages and use this message as a baseline. I then introduced my problem (not making sales). Then I introduced the key players in the conversation and their roles. Finally, I used a separator, then asked for what I was seeking — a title, description, and 7 keywords.&lt;/p&gt;

&lt;p&gt;As I mentioned, resetting the conversation may not always be effective so it may be best to start fresh with a new conversation. What you should definitely do is introduce your problem, think about people you’d like to have on your “team” if you were solving this problem together, and specify what their focus is in the conversation&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of Directed Conversation
&lt;/h3&gt;

&lt;p&gt;This strategy of directed conversation, using human language as a programming language, has the potential to greatly improve the problem-solving abilities of AI like ChatGPT. By providing clear direction and context, we can guide the AI towards more accurate and useful predictions. This can help to avoid the issue of “hallucinations” and make the AI a more reliable and effective tool.&lt;/p&gt;

&lt;p&gt;In my case, this approach helped ChatGPT to generate more effective titles, descriptions, and keywords for my coloring books. It also helped me to avoid potential legal issues by ensuring that all suggestions were legally sound.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lvTgqA3f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AE1BiC7EJoXBc5RoqoBZFAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lvTgqA3f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AE1BiC7EJoXBc5RoqoBZFAg.png" alt="" width="561" height="1547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing This Approach
&lt;/h3&gt;

&lt;p&gt;Ok, but was it really effective? What would happen for instance if someone purposefully asked one of the players to do something legally questionable? 😅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QIqR_iGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ALgDsO_7oKNs0oHddqDGUKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QIqR_iGX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ALgDsO_7oKNs0oHddqDGUKQ.png" alt="" width="635" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Looking Ahead
&lt;/h3&gt;

&lt;p&gt;As AI continues to evolve, I believe that strategies like role-playing will become increasingly important. They allow us to harness the power of AI in a more controlled and directed way, leading to better outcomes and fewer errors. As software developers, we are in a unique position to leverage these strategies due to our well-honed ability to direct, shape, and create software applications using language (natural and otherwise).&lt;/p&gt;

&lt;p&gt;So, while AI may be changing the landscape of software development, I see it as an opportunity rather than a threat. By embracing new strategies and approaches, we can continue to innovate and create value in this exciting field. And who knows? Maybe one day, we’ll all be having conversations with entire codebases, refactoring them to our heart’s content with a mere phrase such as “Make this codebase more modular”.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Use Xcode's Template Library To Reduce Boredom</title>
      <dc:creator>Kenny Dubroff (froggomad)</dc:creator>
      <pubDate>Tue, 24 Nov 2020 15:39:11 +0000</pubDate>
      <link>https://dev.to/froggomad/how-i-use-xcode-s-template-library-to-reduce-boredom-1gcp</link>
      <guid>https://dev.to/froggomad/how-i-use-xcode-s-template-library-to-reduce-boredom-1gcp</guid>
      <description>&lt;p&gt;If you're anything like me, you make a lot of Xcode projects. You also may have noticed that if you like your projects organized a certain way, perhaps by a certain paradigm - then you're doing a lot of repetitive, boring work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repetitive, boring, work?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  But... I'm a programmer
&lt;/h4&gt;

&lt;p&gt;I know, right? Aren't we supposed to be automating things? I think we are. So why the heck are we manually rearranging our files and folders? Haven't we noticed yet that we can create different kinds of projects in Xcode and they come with different files and folders? &lt;/p&gt;

&lt;h2&gt;
  
  
  Have you ever wondered just how they generate all that code? Me too, so let's find out...
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What exactly can you generate with a template?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;files&lt;/em&gt;, folders, groups, &lt;em&gt;dynamic lines of code&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;In this tutorial, we'll be building a simple file template with dynamically generated code. Trust me... you definitely don't want me to cover everything you can do with a template in one tutorial. It's &lt;strong&gt;a lot&lt;/strong&gt; - you can even customize entire projects up to and beyond editing and adding entries to your &lt;code&gt;info.plist&lt;/code&gt; file. &lt;/p&gt;

&lt;h2&gt;
  
  
  Generating Files
&lt;/h2&gt;

&lt;h4&gt;
  
  
  With this:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SuTUTtGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rn7wa9gn73lyedpdh05s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SuTUTtGs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rn7wa9gn73lyedpdh05s.png" alt="Screen Shot 2020-11-24 at 6.18.07 AM" width="800" height="222"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  You'll get to make a model file that conforms to Equatable, each time with a different name for the file and class:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bx64fOsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/esaz4v695998rdjgfbjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bx64fOsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/esaz4v695998rdjgfbjv.png" alt="Screen Shot 2020-11-24 at 6.14.04 AM" width="731" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  File-&amp;gt;New-&amp;gt;File Dialog
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zcFuZzq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xmrshfet8xyyewvk2g1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zcFuZzq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xmrshfet8xyyewvk2g1t.png" alt="Screen Shot 2020-11-24 at 6.16.26 AM" width="733" height="521"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h4&gt;
  
  
  New Model With Equatable Conformance!
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xAq4wQtd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8zjly14jua4fx2kn5nbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xAq4wQtd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8zjly14jua4fx2kn5nbl.png" alt="Screen Shot 2020-11-24 at 6.18.58 AM" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Anatomy of a Template
&lt;/h1&gt;

&lt;p&gt;At their core, templates are pretty simply woven together. You have a folder with the extension &lt;code&gt;.xctemplate&lt;/code&gt; and a &lt;code&gt;.plist&lt;/code&gt; file in that folder named &lt;code&gt;TemplateInfo.plist&lt;/code&gt;. From there, you can make things pretty complex, but it's easy to get "in the weeds" pretty quickly. We could generate a file solely in the &lt;code&gt;TemplateInfo.plist&lt;/code&gt; file if we use the right options and do everything just right, but let's keep this simple and see how you can start putting the Xcode Template engine to use right away to cut down on a little bit of boilerplate code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Find the Folder Where Custom Templates Go
&lt;/h2&gt;

&lt;p&gt;Xcode's default templates live in various places inside of the Xcode App Package. We could store our templates there, but then every time we update the Xcode app, they'll get replaced. The good news is, we have a place where we can more permanently store our templates.&lt;/p&gt;

&lt;p&gt;Open up your finder window, and press &lt;code&gt;cmd&lt;/code&gt;+&lt;code&gt;shift&lt;/code&gt;+&lt;code&gt;g&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mo5d6rwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qlpt7274i3aiz4ucpp49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mo5d6rwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qlpt7274i3aiz4ucpp49.png" alt="Screen Shot 2020-11-24 at 6.34.38 AM" width="435" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type in the following path &lt;code&gt;~/Library/Developer/Xcode/Templates&lt;/code&gt; and click Go&lt;/p&gt;

&lt;p&gt;Congrats! You're inside of the custom template folder. Now let's create our first custom template. The first thing you'll want to do is create 2 separate folders to organize your Templates. Name one &lt;code&gt;File Templates&lt;/code&gt; and the other &lt;code&gt;Project Templates&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Create Your Template Folder
&lt;/h1&gt;

&lt;p&gt;Now, open the &lt;code&gt;File Templates&lt;/code&gt; folder, and create a new folder. Name this whatever you'd like, but make sure to end the folder name with &lt;code&gt;.xctemplate&lt;/code&gt;. For example, &lt;code&gt;devTo.xctemplate&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Create Your &lt;code&gt;TemplateInfo.plist&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Inside of the &lt;code&gt;xctemplate&lt;/code&gt; folder you just created, we're going to need to create a &lt;code&gt;TemplateInfo.plist&lt;/code&gt; file. This is kind of like template inception, but let's create a new &lt;code&gt;.plist&lt;/code&gt; file using Xcode's existing &lt;code&gt;.plist&lt;/code&gt; file template.&lt;/p&gt;

&lt;p&gt;Open up Xcode and choose &lt;code&gt;File-&amp;gt;New-&amp;gt;File&lt;/code&gt;. Select Property list (I like to filter the files so it's easier to find).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vmb68bd9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/td029esrcjw0dggbne4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vmb68bd9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/td029esrcjw0dggbne4s.png" alt="Screen Shot 2020-11-24 at 6.43.13 AM" width="733" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you'll need to navigate to the &lt;code&gt;xctemplate&lt;/code&gt; folder you just created in &lt;code&gt;~/Library/Developer/Xcode/Templates&lt;/code&gt;. ⚠️Important!⚠️ name this file &lt;code&gt;TemplateInfo.plist&lt;/code&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  NOTE: Sometimes the easiest way to put this file in the right folder is to save it to your desktop, then move it there manually using &lt;code&gt;cmd&lt;/code&gt;+&lt;code&gt;shift&lt;/code&gt;+&lt;code&gt;g&lt;/code&gt; in Finder.
&lt;/h4&gt;

&lt;h1&gt;
  
  
  4. Start Populating Your &lt;code&gt;TemplateInfo.plist&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Once you've created the &lt;code&gt;TemplateInfo.plist&lt;/code&gt; file and have it in the right directory, it's time to create your template! Open your &lt;code&gt;TemplateInfo.plist&lt;/code&gt; file and create a new entry by clicking the small plus sign that appears when you hover over an existing row.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yTamxXjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xj4rs3k25x0mgv8amq1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yTamxXjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xj4rs3k25x0mgv8amq1q.png" alt="Screen Shot 2020-11-24 at 6.51.27 AM" width="653" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Identify what type of template this is.
&lt;/h3&gt;

&lt;p&gt;By default this shows a list of values such as &lt;code&gt;Bundle Identifier&lt;/code&gt;. We're first going to identify this template as a file template. In order to do that, we'll need to name this entry &lt;code&gt;Kind&lt;/code&gt;. Leave the type as String and double click where the value would be to input a new value. &lt;/p&gt;

&lt;p&gt;Copy and paste &lt;code&gt;Xcode.IDEKit.TextSubstitutionFileTemplateKind&lt;/code&gt;, and Xcode will know this is a file template rather than project template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c9WobEYT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/s27pwkr7qq7x6p69kzp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c9WobEYT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/s27pwkr7qq7x6p69kzp9.png" alt="Screen Shot 2020-11-24 at 7.02.41 AM" width="800" height="75"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Identify which platform(s) this template can be used on.
&lt;/h3&gt;

&lt;p&gt;We'll use this on iOS. Create a new Entry named &lt;code&gt;Platforms&lt;/code&gt; and change the type to &lt;code&gt;Array&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HJdVVBkm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ebs7n0732se5e3dfvxvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HJdVVBkm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ebs7n0732se5e3dfvxvv.png" alt="Screen Shot 2020-11-24 at 7.04.45 AM" width="715" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, click the small dropdown next to Platforms and create a new entry. This should create Item 0. For the value, enter &lt;code&gt;com.apple.platform.iphoneos&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nCkvqdtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g2vm2vkjqi6qkt0zuek1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nCkvqdtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g2vm2vkjqi6qkt0zuek1.png" alt="Screen Shot 2020-11-24 at 7.07.20 AM" width="800" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Create Options
&lt;/h1&gt;

&lt;p&gt;Collapse Platforms and create a new entry called Options. Make this an &lt;code&gt;Array&lt;/code&gt;. Options is an Array that contains Dictionaries. These Dictionaries define text boxes, checkboxes, dropdowns, combo boxes, and static text. Each gets its own unique identifier and can be used to populate fields. &lt;/p&gt;

&lt;p&gt;First, we're going to create an option with an Identifier of &lt;code&gt;productName&lt;/code&gt;. &lt;code&gt;productName&lt;/code&gt; is a special identifier that can be referenced throughout the template as either &lt;code&gt;___FILEBASENAME___&lt;/code&gt; or &lt;code&gt;___FILEBASENAMEASIDENTIFIER___&lt;/code&gt;. &lt;code&gt;FILEBASENAME&lt;/code&gt; references the name exactly as input while &lt;code&gt;FILEBASENAMEASIDENTIFIER&lt;/code&gt; references the name in a way that can be used for class names, variables, and more by stripping out special characters and spaces.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Expand the Options Array and create a new entry. 

&lt;ul&gt;
&lt;li&gt;Make this type Dictionary. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Expand the Dictionary (item 0) and create a new entry.

&lt;ul&gt;
&lt;li&gt;Name this Identifier. Give it a value of &lt;code&gt;productName&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry in the Dictionary named Description.

&lt;ul&gt;
&lt;li&gt;Give it a value of "&lt;code&gt;Enter Name&lt;/code&gt;" (no quotes)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry named Name.

&lt;ul&gt;
&lt;li&gt;Give it a value of "&lt;code&gt;Enter Name&lt;/code&gt;"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry named Default.

&lt;ul&gt;
&lt;li&gt;Give it a value of "&lt;code&gt;Model Name&lt;/code&gt;"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry named Required. Make the Type Boolean

&lt;ul&gt;
&lt;li&gt;Give it a value of 1 (true)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a new entry named Type.

&lt;ul&gt;
&lt;li&gt;Give it a value of text&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--An9JVvS3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/it93ap5qq014i4tlt7nt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--An9JVvS3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/it93ap5qq014i4tlt7nt.png" alt="Screen Shot 2020-11-24 at 7.26.16 AM" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Here's what this does:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;2. Our default identifier we use in the file.&lt;/li&gt;
&lt;li&gt;3. The tooltip that appears when you hover over the option&lt;/li&gt;
&lt;li&gt;4. The text that appears next to the option&lt;/li&gt;
&lt;li&gt;5. The option's default value&lt;/li&gt;
&lt;li&gt;6. Whether or not the option is required to have a valid value in order to create the template.&lt;/li&gt;
&lt;li&gt;7. The type of option this is. Text makes this a text box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  6. Create Your File!
&lt;/h1&gt;

&lt;p&gt;I like to do this from terminal to get a fresh file, but you can do it from Xcode and use the blank template or Swift File template. Using the Swift File template includes the header though, and you can choose to include or exclude it with your own blank file.&lt;/p&gt;

&lt;p&gt;No matter your method, create a new file named &lt;code&gt;___FILEBASENAME___.swift&lt;/code&gt;. This will name the file after whatever you type in the text box when you choose this template in Xcode.&lt;/p&gt;

&lt;p&gt;I'm going to create a model file with the header included (&lt;code&gt;___FILEHEADER___&lt;/code&gt;). Feel free to make whatever you'd like! 🧑‍💻👩‍💻&lt;/p&gt;

&lt;p&gt;Anywhere you would normally type the name of the file/struct/class/whatever - you can substitute that with &lt;code&gt;___FILEBASENAMEASIDENTIFIER___&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P8WiXOb8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l2vuop0spmm5kxknj7a1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P8WiXOb8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l2vuop0spmm5kxknj7a1.png" alt="Screen Shot 2020-11-24 at 7.31.31 AM" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save this file in the same place you saved your TemplateInfo.plist file. Now, the next time you open Xcode, go to &lt;code&gt;File-New-&amp;gt;File&lt;/code&gt; and behold the glory of your template!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KVYhbi7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qaua2ystpk32qqivuqae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KVYhbi7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qaua2ystpk32qqivuqae.png" alt="Screen Shot 2020-11-24 at 7.49.47 AM" width="738" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K4hj4U3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3999ujwihu3dizdhm1yh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K4hj4U3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3999ujwihu3dizdhm1yh.png" alt="Screen Shot 2020-11-24 at 7.50.16 AM" width="731" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UNe1-PPS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/r7cu6dscv8qu7tccx4zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UNe1-PPS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/r7cu6dscv8qu7tccx4zc.png" alt="Screen Shot 2020-11-24 at 7.50.40 AM" width="800" height="384"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h1&gt;
  
  
  Free From Boredom, Safe From Mistakes
&lt;/h1&gt;

&lt;p&gt;I've created several file templates and a few project templates of my own, some that I use on a frequent basis. This helps me not waste so much time typing boilerplate code because I only have to make one template and it's done &lt;strong&gt;forever&lt;/strong&gt;. More importantly, it gives me the confidence and security knowing that my initial implementation will work, because it worked last time. Create your templates with the best of care and intentions, and you have something you can use that's safe, reliable, and &lt;strong&gt;fast&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Drop a note in the comments about your experience with Xcode Templates.&lt;/p&gt;

&lt;h4&gt;
  
  
  Happy Templating!
&lt;/h4&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>devops</category>
      <category>codequality</category>
    </item>
    <item>
      <title>How To Use DispatchGroups To Gather Information From Multiple Sources At Once</title>
      <dc:creator>Kenny Dubroff (froggomad)</dc:creator>
      <pubDate>Fri, 23 Oct 2020 16:35:43 +0000</pubDate>
      <link>https://dev.to/froggomad/multiple-network-calls-one-completion-2572</link>
      <guid>https://dev.to/froggomad/multiple-network-calls-one-completion-2572</guid>
      <description>&lt;h4&gt;
  
  
  Before We Begin
&lt;/h4&gt;

&lt;h5&gt;
  
  
  It's helpful, but not required to know:
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Basic Swift&lt;/li&gt;
&lt;li&gt;Object-Oriented Programming (OOP)&lt;/li&gt;
&lt;li&gt;Asynchronous programming&lt;/li&gt;
&lt;li&gt;&lt;code&gt;URLSession&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What We'll Be Doing
&lt;/h1&gt;

&lt;p&gt;Let's say you're creating a simple catalog of Car Brands. For each brand, you want to know what makes and models the brand has available. You have an API with the information and it's in JSON. In Swift, we might model something like that in this fashion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;CarBrand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Codable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Codable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then if we were so fortunate, we'd make one API call, get an array or two of associated data, and get all of the information we want. Ah, bliss...&lt;/p&gt;

&lt;h2&gt;
  
  
  This time, things wouldn't be so easy...
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Linking information from decoupled sources.
&lt;/h4&gt;

&lt;p&gt;I recently ran into a problem where I had to do something similar in a totally unexpected way. I was downloading information from a single source, but for some reason, relationships couldn't be established properly at the parent endpoint and we had to access a pivot table where the relationship between the two objects existed. We could then go and retrieve information about the related object from another endpoint.&lt;/p&gt;

&lt;p&gt;In other words, parents had no information about their children. So in order to link properties, it was necessary to initiate one network call, wait for several other network calls to come back, then complete our method. This was what the JSON from the base URL (&lt;code&gt;/brand&lt;/code&gt;) looked something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"AmazingCarBrand"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"AnotherAmazingBrand"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I described, all we get is information about the brand itself. It was then necessary to find the linked pieces at their own endpoints, and use a middleman (pivot table) endpoint to figure out which children to retrieve. Here's sample JSON from a pivot table (&lt;code&gt;/brand/details/id&lt;/code&gt;) endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"brandid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"makeids"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could then go to the &lt;code&gt;/make/id&lt;/code&gt; endpoint to get the following JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Junker"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... then repeat the middleman/pivot table process to get information on models for each make. But for "simplicity's" sake I'll stop this tutorial one level deep.&lt;/p&gt;

&lt;h4&gt;
  
  
  This doesn't easily facilitate OOP
&lt;/h4&gt;

&lt;p&gt;My team's goal was to do things in an Object-Oriented way, so instead of coming away from a method with a bunch of separate arrays at different times, we wanted to just have one object that had at least the top-level child objects as properties so we could use what we needed when we needed, and keep the data coupled where it needs to be... the way we typically expect things.&lt;/p&gt;

&lt;h4&gt;
  
  
  No big deal right, just use a loop...
&lt;/h4&gt;

&lt;p&gt;Well, yeah - a loop is definitely part of what's necessary here... a couple of them actually (if we needed another property, or to go another level deep such as getting models). But when we're working in an asynchronous environment (which Networking automatically is) we don't know when we'll be getting the information we need back from the remote source. In our case, this means our Car Brand will have an incomplete list of Makes and/or Models - even though we made requests to get that information through those loops... unless we had a way of knowing when those requests were also complete.&lt;/p&gt;

&lt;p&gt;I was using a &lt;a href="https://medium.com/swlh/developing-a-reusable-networking-class-66ef1f7566f"&gt;URLSession Wrapper&lt;/a&gt; so it was a little cleaner, and I promise (🤞) I knew it wouldn't work... but my initial implementation looked something like this after making the initial call to get brands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// "https://www.example.com/base/brands"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://www.example.com/base/brands"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="c1"&gt;/// "https://www.example.com/base/brands/details"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;baseDetailURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseURL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendingPathComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// get Make information for one CarBrand&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getMakeInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CarBrand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getMakeModelIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="c1"&gt;// the ids that come back are optional, so we need to unwrap them&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no ids came back from makeModelId request"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// initialize an empty array of CarMake&lt;/span&gt;
        &lt;span class="c1"&gt;// to hold our objects when they come back&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// this URL has information about which makes a brand has&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;brandMakeDetailURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseDetailURL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendingPathComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;brandMakeDetailRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brandMakeDetailURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brandMakeDetailRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error getting make details: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="c1"&gt;// Normally I would continue here, but we get an error&lt;/span&gt;
                    &lt;span class="c1"&gt;// that we're outside of a loop. Because we're asynchronously&lt;/span&gt;
                    &lt;span class="c1"&gt;// programming, we're no longer on the same thread as our loop.&lt;/span&gt;
                    &lt;span class="c1"&gt;// We're on some background thread waiting for a response&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;carMake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carMake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error decoding CarMake: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getMakeModelIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CarBrand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// implementation here&lt;/span&gt;
    &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why didn't this work?
&lt;/h3&gt;

&lt;p&gt;Because we're asynchronously programming, when we get to the part where we loop through ids and make requests, the requests are made immediately, not waiting for a response before making the next request. When we finish the loop, we may get one or two responses back, but the rest are still out in the ether.&lt;/p&gt;

&lt;p&gt;What we need is a signal to know when all of the makes and models have come back and have been linked to the brand... what we need is a basic implementation to make sure I'm right before we get into this any deeper!&lt;/p&gt;

&lt;p&gt;My initial idea was to keep count using a placeholder &lt;code&gt;Int&lt;/code&gt; property that I would increment as requests completed. There was then a conditional check that would complete the method with the entire array after every request had come back with a response.&lt;/p&gt;

&lt;h3&gt;
  
  
  And it worked!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="c1"&gt;// we're in the completion here meaning&lt;/span&gt;
    &lt;span class="c1"&gt;// this cal has come back, so increment    &lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;carMake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carMake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error decoding CarMake: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;       
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it worked, it just didn't feel... right. I'm sure this is fine, though it could probably use more error handling and the code could be more reusable. But those weren't the issues I was having. I just knew there was a built-in way to do this because I had used different methods to do things like this before; just not often enough to remember.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did I Need A &lt;code&gt;Semaphore&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;A semaphore was my initial thought, and I did some preliminary research, and it seemed to check out. A semaphore allows you to start &lt;code&gt;n&lt;/code&gt; tasks, and signal when they're complete. As I went through implementations though, the logic just wasn't tracking for me. So I started looking into other methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Was using a &lt;code&gt;DispatchGroup&lt;/code&gt; the answer I was seeking?
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;DispatchGroup&lt;/code&gt; (&lt;code&gt;group&lt;/code&gt;) is an object that holds a group of &lt;code&gt;n&lt;/code&gt; tasks. Tasks enter a &lt;code&gt;group&lt;/code&gt; when they begin their task and leave a &lt;code&gt;group&lt;/code&gt; when they finish.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DispatchGroup&lt;/code&gt; then has a &lt;code&gt;notify&lt;/code&gt; method that checks to see if the &lt;code&gt;group&lt;/code&gt; is empty as a task leaves. If it is, the code inside of the &lt;code&gt;notify&lt;/code&gt; block gets executed. Perfect!&lt;/p&gt;



&lt;h4&gt;
  
  
  But doesn't a Semaphore work the same?
&lt;/h4&gt;

&lt;p&gt;Yes, and no. A &lt;code&gt;Semaphore&lt;/code&gt; probably also would've worked here, but a &lt;code&gt;Semaphore&lt;/code&gt; is more for limiting the number of tasks that can run concurrently. For instance, only allowing one login from one device at a time to prevent DDOS attacks to your login server.&lt;/p&gt;

&lt;p&gt;A DispatchGroup is for allowing &lt;code&gt;n&lt;/code&gt; tasks to run before completing.&lt;/p&gt;

&lt;p&gt;While similar, a &lt;code&gt;DispatchGroup&lt;/code&gt; is really what's appropriate here.&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally, let's implement our &lt;code&gt;DispatchGroup&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// get Make information for one CarBrand&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getMakeInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CarBrand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getMakeModelIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="c1"&gt;// the ids that come back are optional, so we need to unwrap them&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no ids came back from makeModelId request"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// initialize an empty array of CarMake&lt;/span&gt;
        &lt;span class="c1"&gt;// to hold our objects when they come back&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// each task enters the group at the beginning of our loop&lt;/span&gt;
            &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="c1"&gt;// this URL has information about which makes a brand has&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;brandMakeDetailURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;baseDetailURL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendingPathComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;brandMakeDetailRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brandMakeDetailURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;brandMakeDetailRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error getting make details: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="c1"&gt;// Normally I would continue here, but we get an error&lt;/span&gt;
                    &lt;span class="c1"&gt;// that we're outside of a loop. Because we're asynchronously&lt;/span&gt;
                    &lt;span class="c1"&gt;// programming, we're no longer on the same thread as our loop.&lt;/span&gt;
                    &lt;span class="c1"&gt;// We're on some background thread waiting for a response&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;carMake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CarMake&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carMake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error decoding CarMake: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="c1"&gt;// each task leaves the group when it's finished&lt;/span&gt;
                &lt;span class="c1"&gt;// you want to make sure if you're exiting the method&lt;/span&gt;
                &lt;span class="c1"&gt;// anywhere else to also exit the group&lt;/span&gt;
                &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// This will complete on the main thread&lt;/span&gt;
        &lt;span class="c1"&gt;// when all tasks complete.&lt;/span&gt;
        &lt;span class="c1"&gt;// If you want to complete on a background&lt;/span&gt;
        &lt;span class="c1"&gt;// thread, you can initialize a new background thread&lt;/span&gt;
        &lt;span class="c1"&gt;// here or use a `DispatchQueue` and pass it in&lt;/span&gt;
        &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;What we've done here is linked multiple dependencies to one object using multiple asynchronous tasks, and we're only completing the top level object when all asynchronous tasks related to it are complete.&lt;/p&gt;

&lt;p&gt;We did this using a &lt;code&gt;DispatchGroup&lt;/code&gt; which allows us to begin multiple asynchronous tasks, and notifies us when they've all finished.&lt;/p&gt;

&lt;p&gt;If we wanted to limit the number of calls we could make at once, we could use a &lt;code&gt;Semaphore&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to go from here
&lt;/h3&gt;

&lt;p&gt;There are certainly a &lt;em&gt;lot&lt;/em&gt; of improvements that can be made to this code. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For one, it could be more modular.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As I mentioned earlier, I normally use a &lt;a href="https://medium.com/swlh/developing-a-reusable-networking-class-66ef1f7566f"&gt;&lt;code&gt;URLSession&lt;/code&gt; Wrapper&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Second, error handling could be improved. Look out for an article from me that links that &lt;code&gt;URLSession&lt;/code&gt; Wrapper to an Error Handler using the &lt;code&gt;Result&lt;/code&gt; Type&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In addition, some of this is assuming "The Happy Path". I believe there are one or 2 places where I'm force-unwrapping Optionals for instance.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Third, we didn't touch on &lt;a href="https://medium.com/swlh/implementing-automatic-codable-1e212b54848"&gt;how JSON Decoding is working using the Codable protocol&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Lastly, if you tried to run any of this code, you got a bunch of decoding errors - this is because &lt;code&gt;www.example.com&lt;/code&gt; isn't hosting JSON for us!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Please go forth and find an API that's structured in a similar way, or string several together... heck - you could roll your own using Firebase or something similar. Play around with DispatchGroups and Queues and see what you can come up with. It's probably the best way to learn.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or you can watch me babble more words ⏬&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
