<?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: leogdion</title>
    <description>The latest articles on DEV Community by leogdion (@leogdion).</description>
    <link>https://dev.to/leogdion</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%2F77395%2Fed0aaaa7-9252-4c81-ab86-a0b8e6278a6f.jpg</url>
      <title>DEV Community: leogdion</title>
      <link>https://dev.to/leogdion</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leogdion"/>
    <language>en</language>
    <item>
      <title>Swift Packages – Dependency Management of the Future</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Wed, 26 May 2021 11:12:18 +0000</pubDate>
      <link>https://dev.to/leogdion/swift-packages-dependency-management-of-the-future-2gdh</link>
      <guid>https://dev.to/leogdion/swift-packages-dependency-management-of-the-future-2gdh</guid>
      <description>&lt;p&gt;Package Management has been around for decades. There’s everything from APT to Maven to chocolatey. For those who work in the Apple space we are probably more familiar with Cocoapods and Homebrew. However since the introduction of Swift, the Apple team has given us a new package manager: &lt;strong&gt;Swift Package Manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  what iOS and other Swift developers can use&lt;/li&gt;
&lt;li&gt;  the advantages of SPM (Swift Package Manager) from its predecessors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, let's get into &lt;strong&gt;why you'd want to use any package manager in the first place&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2F030-puzzle-17054.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2F030-puzzle-17054.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modularity and Reuse - Benefits of Package Management
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One key component of package management is the ability to share code or an executable&lt;/strong&gt; - whether that's publicly or just within your internal dev team.&lt;/p&gt;

&lt;p&gt;Part of doing that is breaking your code into separate pieces. This is where package managers encourage &lt;strong&gt;modularization&lt;/strong&gt;. In other words components can be separated out, tested properly, and used by others.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BTG7e_60zN8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Once you’ve separated that piece of functionality, you can include support across a variety of devices and operating systems. &lt;strong&gt;In the Apple ecosystem, this could mean supporting not only the iPhones but anything from Linux servers to the Apple Watch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another nice feature of package management is that you can lock onto specific versions. Usually you can specify a &lt;em&gt;&lt;a href="https://semver.org" rel="noopener noreferrer"&gt;semver&lt;/a&gt;&lt;/em&gt; compatible version number related to a version tag or even a branch name. Let's get into the different package managers for developers in the Apple ecosystem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2Fpasted-image-small-14348.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2Fpasted-image-small-14348.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Came Before... and is Still Around
&lt;/h2&gt;

&lt;p&gt;Swift Package Manager is fairly a new addition for Swift developers let alone iOS and macOS developers. Let's talk about what what has come before for developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Carthage&lt;/strong&gt; has been around since the advent of Swift. Carthage really specializes in building the binary frameworks and sharing those within your project. Before Carthage, there was &lt;strong&gt;CocoaPods&lt;/strong&gt; which has been around since the early days of Objective-C.&lt;/p&gt;

&lt;p&gt;One drawback is that Cocoapods is built in Ruby and is therefore dependent on having the correct versions of Ruby installed while Carthage is built in Swift. Another drawback for Cocoapods is that &lt;strong&gt;it requires modification of your Xcode projects and workspaces&lt;/strong&gt;. Carthage gets around this by having the user &lt;strong&gt;add the built frameworks the manually the first time they integrate it.&lt;/strong&gt; If you are interested in some of the choices where Carthage differs from Cocoapods, check out &lt;a href="https://github.com/Carthage/Carthage#differences-between-carthage-and-cocoapods" rel="noopener noreferrer"&gt;this piece the Carthage README.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, if neither works for your project, there's &lt;strong&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules" rel="noopener noreferrer"&gt;git submodules&lt;/a&gt;&lt;/strong&gt;. Git Submodules are the most difficult to deal with, but perhaps the most versatile. They simply require an available git repo to link to a subdirectory. If you plan editing your dependency, git submodules may be required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are going to use a package manager, choose one at best and stick with it.&lt;/strong&gt; However your best bet is migrating to Swift Package Manager.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2FXcode_Icon-small-15043.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F04%2FXcode_Icon-small-15043.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Swift Package Manager?
&lt;/h2&gt;

&lt;p&gt;Swift Package Manager brings plenty of benefits along with it. Along with it's versatile handing of versioning, SPM (Swift Package Manager) is natively supported in Swift. While tools like CocoaPods require Ruby and other Gem dependencies, there's no need with SPM. SPM simply requires either Swift or Xcode be installed on your macOS or Linux machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPM is also open-source while also being supported by Apple. This means you get the benefits of seeing how something works and being open to the community as well as in Apple's best interest to support it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Really it comes down to whether your current line of dependencies support SPM. At this point, the list of Cocoapods and Carthage packages which also support SPM continues to grow as SPM expands its support for features like binary packages (i.e. XCFrameworks).&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2ZhvfG_vd5Y"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Not only does SPM provide benefits in your Xcode projects but also in the way you modularize and share your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Publish with Swift Package Manager?
&lt;/h2&gt;

&lt;p&gt;There are plenty of reasons to break apart your application or even publish your library or executable via Swift Package Manager. For one thing, &lt;strong&gt;it becomes easier to build your application completely in Swift - from server to device.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Stack Swift
&lt;/h3&gt;

&lt;p&gt;For instance, you can build your supporting server application in Swift whether that’s Vapor, Lambda, Smoke, or Hummingbird. By doing that, &lt;strong&gt;you can share code between client (iOS application) and server.&lt;/strong&gt; Specifically Codable models can be shared on both iOS and the server. Even if you have an existing server, you can build a mock server in Swift for testing.&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;// an example of sharing server-side and client-side code via SPM&lt;/span&gt;

    &lt;span class="c1"&gt;// HeartwitchKit/WorkoutData.swift&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;WorkoutData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;heartRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;heartRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heartRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heartRate&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WorkoutData&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;WorkoutData&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;heartRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heartRate&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heartRate&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;WorkoutData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;heartRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;heartRate&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;extension&lt;/span&gt; &lt;span class="kt"&gt;WorkoutData&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="c1"&gt;// HeartwitchKitServer/WorkoutData&lt;/span&gt;
    &lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Vapor&lt;/span&gt;
    &lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;WorkoutData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are going the route of building both ends of your application in Swift, SPM is the only way to go. In fact for parts of your code that can be abstracted away from the device, SPM has advantages over Xcode when it comes to testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testability
&lt;/h3&gt;

&lt;p&gt;The ease of testing through SPM is really nice as well. Especially when it’s difficult and slow to do in simulator. For instance before Xcode 12.5 supported watchOS testing, it was nearly impossible to run unit tests for watchOS.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/fzLkHAku1mc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;However by having most of your Apple Watch application code in a Swift package, I can easily test code which doesn't require watchOS specifically. &lt;strong&gt;This circumvents the issue but also makes it easier without needing an actual device or via simulator.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In spots where code is only applicable and available on the watch, such as SwiftUI or HealthKit code I can use a combination of preprocessor directives to mark availability:&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;// using canImport and os to disable applicable code&lt;/span&gt;

    &lt;span class="cp"&gt;#if canImport(HealthKit)&lt;/span&gt;
      &lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;HealthKit&lt;/span&gt;

      &lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;HKHealthStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HealthInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;workout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;withConfiguration&lt;/span&gt; &lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WorkoutConfiguration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Workout&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;hkConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HKWorkoutConfiguration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;hkConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;healthKitType&lt;/span&gt;
          &lt;span class="cp"&gt;#if os(watchOS)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;HealthKitLiveWorkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fromHealthStore&lt;/span&gt;&lt;span class="p"&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;withConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hkConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="cp"&gt;#else&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;HealthKitWorkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fromHealthStore&lt;/span&gt;&lt;span class="p"&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;withConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hkConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="cp"&gt;#endif&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only that but as I develop a server-side application I may not want to run the watchOS application every time to test capabilities on the server. This is where refactoring into a Swift package is also useful. By having a library which contains most of my watchOS code, I can simulate the heart rate in the Apple Watch application by creating a simple command line application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command Line Tools
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SPM allows me to duplicate the functionality of Heartwitch, my watchOS app, into a command line tool&lt;/strong&gt; which replicates the heart rate sensor feature. This makes it easier to test the server application without having to run the Heartwitch app on my Apple Watch or via simulator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F05%2Fhwmonitor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2021%2F05%2Fhwmonitor.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of my favorite tools out there is &lt;a href="https://github.com/apple/swift-argument-parser" rel="noopener noreferrer"&gt;the Swift Argument Parser by the Swift team&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swift Argument Parser builds on the great ideas from Swift UI (i.e. Property Wrappers) and Codable and brings that to the command line.&lt;/strong&gt; You can do things like subcommands, helpful feedback, options, and flags. In my case, I use it to enable faster server-side development. Specifically I built a command line tool to replicate the heart rate monitoring feature of the Apple Watch app and feed my server simulated heart rates.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/SeaRbgIkmW4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Power of SPM
&lt;/h2&gt;

&lt;p&gt;In this article we covered package management and the advantages of SPM over other managers. Consider using SPM and learning the ins and outs of integrating Swift Packages into your projects. If you are using Cocoapods or Carthage, consider migrating your applications over. In the next article, I'll talk about creating a Swift Package from scratch as well as the most important part - Package.swift - the Swift Package Manifest file.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftpackagemanager</category>
      <category>dependencymanagement</category>
      <category>ios</category>
    </item>
    <item>
      <title>Combine &amp; CoreLocation, Part 3 - Integrations with flatMap</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Tue, 01 Sep 2020 15:50:34 +0000</pubDate>
      <link>https://dev.to/leogdion/combine-corelocation-part-3-integrations-with-flatmap-fj</link>
      <guid>https://dev.to/leogdion/combine-corelocation-part-3-integrations-with-flatmap-fj</guid>
      <description>&lt;p&gt;In our &lt;a href="https://learningswift.brightdigit.com/combine-corelocation-receiving-handling-events/"&gt;previous post&lt;/a&gt;, I explained how to hook up our new CLManagerDelegate publishers for CLAuthorizationStatus to the ObservableObject using Combine. In this post, we be transforming the CLLocation publisher data into something useful using flatMap and the built-in publisher, Sequence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learningswift.brightdigit.com/combine-corelocation-publishers-delegates/"&gt;Creating Publishers from Delegates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learningswift.brightdigit.com/combine-corelocation-receiving-handling-events/"&gt;Using Function Reactive Programming to Transform Values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understanding FlatMap and Built-In Publishers&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Combine for Complex Transformations
&lt;/h2&gt;

&lt;p&gt;While we can simply assign the value from the authorizationPublisher to our authorizationStatus property, locationPublisher requires more work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&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="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerCombineDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerDelegate&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;locationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&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 our locationPublisher returns a &lt;code&gt;[CLLocation]&lt;/code&gt; result, our location property is &lt;code&gt;CLLocation?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is to say we are going to need to do some functional programming to transform the result of our publisher:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turn the Array itself into a Sequential Publisher of each value&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;flatMap&lt;/code&gt; to return a new Publisher&lt;/li&gt;
&lt;li&gt;Cast the CLLocation into the matching &lt;code&gt;CLLocation?&lt;/code&gt; (i.e. &lt;code&gt;Optional&amp;lt;CLLocation&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is our result:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;      &lt;span class="n"&gt;locationPublisher&lt;/span&gt;
        &lt;span class="c1"&gt;// convert the array of CLLocation into a Publisher itself&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;:))&lt;/span&gt;
        &lt;span class="c1"&gt;// in order to match the property map to Optional&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// since this is used in the UI,&lt;/span&gt;
        &lt;span class="c1"&gt;//  it needs to be on the main DispatchQueue&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="c1"&gt;// store the value in the location property&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let’s break each of these steps down starting with &lt;code&gt;Publishers.Sequence&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Built-In Publishers from Combine
&lt;/h3&gt;

&lt;p&gt;Combine comes with several built-in Publishers we can use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Just&lt;/code&gt; - single value&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Future&lt;/code&gt; - handling asynchronous callbacks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sequence&lt;/code&gt; - publishing individual values from a sequence in order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We already talked about &lt;code&gt;Just&lt;/code&gt; which takes in a single value. Another popular built-in publisher to use with asynchronous calls is &lt;code&gt;Future&lt;/code&gt; which takes in a result type for when a call is completed. In this case, we are using &lt;code&gt;Sequence&lt;/code&gt; which transforms a sequence type object into a Publisher stream of sequential values. Therefore when CLLocationManagerDelegate receives multiple locations, the publisher acts as if each location from that array received in order.&lt;/p&gt;

&lt;p&gt;However, as &lt;code&gt;Just&lt;/code&gt; is a Publisher so is &lt;code&gt;Sequence&lt;/code&gt;, therefore we can not use &lt;code&gt;.map&lt;/code&gt; but &lt;code&gt;.flatMap&lt;/code&gt; since we want the values from the Publisher not the publisher itself. &lt;code&gt;flatMap&lt;/code&gt; is especially powerful in Combine since it allows us to integrate Publishers from multiple technologies.&lt;/p&gt;
&lt;h3&gt;
  
  
  Integrations in Combine
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://learningswift.brightdigit.com/flatmap-double-optionals-functional-programming/"&gt;I’ve talked previously about what &lt;code&gt;flatMap&lt;/code&gt; does in the functional sense whether that be Arrays or Optionals.&lt;/a&gt; The same goes for Publishers as well.&lt;/p&gt;

&lt;p&gt;Here’s an example of a piece of code to download json from &lt;strong&gt;&lt;a href="https://baconipsum.com/json-api/"&gt;the Bacon Ipsum JSON API&lt;/a&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="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;url&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://baconipsum.com/api/?type=all-meat&amp;amp;sentences=1&amp;amp;format=json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;urlPublisher&lt;/span&gt; &lt;span class="o"&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;dataTaskPublisher&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;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(\&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="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="nv"&gt;type&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="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;decoder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceError&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="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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This uses the dataTaskPublisher available on URLSession and transforms it to a single String. Here is step-by-step how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create DataTaskPublisher from URL&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;map&lt;/code&gt; function to get the &lt;code&gt;data&lt;/code&gt; property from the tuple&lt;/li&gt;
&lt;li&gt;Decode the JSON into an Array of Strings&lt;/li&gt;
&lt;li&gt;In order to assign the value, we change the Failure type to Never. In this case, we are replacing each Error instance with an empty Array of Strings.&lt;/li&gt;
&lt;li&gt;Lastly, we use compactMap to get the first string and therefore ignore all empty Arrays.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Depending on your app and the data you are looking for, you’ll want change the transformations and error handle but typically this is the basics for handling a data task in Combine.&lt;/p&gt;
&lt;h3&gt;
  
  
  Combine System Publishers with &lt;code&gt;flatMap&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Along with URLSession.dataTaskPublisher there are other System publishers available to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;URLSession.dataTaskPublisher&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NotificationCenter.publisher&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Key Value Observation via &lt;code&gt;NSObject.publisher&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Timer.publisher&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this in mind, let’s use the Timer publisher and use flatMap to update our String from the Bacon Ipsum JSON API at a regular interval. Firstly, let’s create a Timer publisher:&lt;br&gt;
&lt;/p&gt;
&lt;div class="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;timerInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;TimeInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;timerPublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;every&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timerInterval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autoconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In this instance, we are creating a Timer publisher on the current RunLoop using the default mode for every 1 second. Lastly is &lt;code&gt;autoconnect&lt;/code&gt; which ensure the publisher connects when subscribed.&lt;/p&gt;

&lt;p&gt;Now we can use flatMap to initiate a new dataTaskPublisher each second:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;timerPublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urlPublisher&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;publishedStringProperty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this we can automate the assignment of the String value, as each dataTask is completed. In other words, our string property will update every second as the url is called.&lt;/p&gt;

&lt;p&gt;Let’s again take a look at our code for updating CLLocation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;      &lt;span class="n"&gt;locationPublisher&lt;/span&gt;
        &lt;span class="c1"&gt;// convert the array of CLLocation into a Publisher itself&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;:))&lt;/span&gt;
        &lt;span class="c1"&gt;// in order to match the property map to Optional&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// since this is used in the UI,&lt;/span&gt;
        &lt;span class="c1"&gt;//  it needs to be on the main DispatchQueue&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="c1"&gt;// store the value in the location property&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;By using Sequence to create a Publisher and flatMap to flatten and return the values from the Sequence Publisher, we have transformed the value from &lt;code&gt;[CLLocation]&lt;/code&gt; to &lt;code&gt;CLLocation&lt;/code&gt; without losing any data.&lt;/p&gt;

&lt;p&gt;However the &lt;code&gt;location&lt;/code&gt; property type and the Publisher result type must match. Therefore since our property takes into not having &lt;code&gt;CLLocation&lt;/code&gt; as a possibility, we need to transform the &lt;code&gt;CLLocation&lt;/code&gt; to an &lt;code&gt;Optional&amp;lt;CLLocation&amp;gt;&lt;/code&gt; (i.e. &lt;code&gt;CLLocation?&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Combine with other Delegates
&lt;/h2&gt;

&lt;p&gt;While I've demonstrated how to use CoreLocation with Combine, this can be useful for other uses of Delegation APIs.&lt;/p&gt;

&lt;p&gt;Recently, I've used these &lt;em&gt;Publicists&lt;/em&gt; in my app, &lt;a href="https://heartwitch.app"&gt;Heartwitch&lt;/a&gt;, which is an Apple Watch app for broadcasting your heart rate to a live stream, as you are playing games or doing presentations. Likewise with HealthKit workouts, I've used the same pattern of creating publishers.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;   
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;coalesce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CoalescePublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;failurePublisist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FailurePublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fullIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FullIdentifierPublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MetadataPublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;OptionalPublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TransitionPublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;workoutCreation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WorkoutCreationPublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;workoutDataUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WorkoutDataUpdatePublicist&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;workoutStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WorkoutStartPublicist&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This same pattern can be used with other Delegation APIs such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CoreBluetooth&lt;/li&gt;
&lt;li&gt;UINotificationCenter&lt;/li&gt;
&lt;li&gt;AVFoundation etc...&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Other Resources
&lt;/h2&gt;

&lt;p&gt;If you are interested in learning more about Combine, I highly recommend checking out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://heckj.github.io/swiftui-notes/"&gt;Using Combine by Joseph Heck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.donnywals.com/"&gt;Donny Wals&lt;/a&gt; and &lt;a href="https://practicalcombine.com/"&gt;His Book Practical Combine&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Donny also appeared on my podcast EmpowerApps.Show:&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/practical-combine-with-donny-wals"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Practical Combine with Donny Wals&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-practical-combine-with-donny-wals" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-practical-combine-with-donny-wals" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-practical-combine-with-donny-wals" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-practical-combine-with-donny-wals" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-practical-combine-with-donny-wals"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/practical-combine-with-donny-wals"&gt;
        &lt;img id="episode-profile-image" alt="Practical Combine with Donny Wals" width="420" height="420" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;For code samples, check out my repositories here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/leogdion/PublisherSample.playground"&gt;https://github.com/leogdion/PublisherSample.playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/brightdigit/CombineAPIHarvesterApp"&gt;https://github.com/brightdigit/CombineAPIHarvesterApp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions or comments on this series, reach out to me on Twitter.&lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Af5A5cq9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/Eg1Y1TBXsAITXkq.png" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SwtsvxxW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1275102891964055553/_cDBegkL_normal.jpg" alt="Leo G Dion still @Home profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Leo G Dion still @Home
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/leogdion"&gt;@leogdion&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      The last on my series of posts on Combine and CoreLocation is out. In this one I explain:&lt;br&gt;🎞Built-in publishers like Just and Sequence&lt;br&gt;🗺Power of flatMap in Combine&lt;br&gt;🚜Using Publishers with other Delegation Pattern APIs&lt;br&gt;&lt;a href="https://t.co/36gWeUvV0m"&gt;buff.ly/32Jlxn9&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      13:52 PM - 01 Sep 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1300793542764306433" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1300793542764306433" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1300793542764306433" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      3
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
If you are interested in learning more about Combine, follow me here on dev.to and I'll let you know when the next Combine or Swift article is out.

</description>
      <category>swift</category>
      <category>swiftui</category>
      <category>reactive</category>
      <category>ios</category>
    </item>
    <item>
      <title>Combine &amp; CoreLocation, Part 2 - Receiving &amp; Handling Events</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Mon, 31 Aug 2020 13:02:35 +0000</pubDate>
      <link>https://dev.to/leogdion/combine-corelocation-part-2-receiving-handling-events-3jgb</link>
      <guid>https://dev.to/leogdion/combine-corelocation-part-2-receiving-handling-events-3jgb</guid>
      <description>&lt;p&gt;&lt;a href="https://learningswift.brightdigit.com/combine-corelocation-publishers-delegates/"&gt;In our previous post,&lt;/a&gt; we talked about how to build a Publisher Factory or Publicist. In this post, we'll talk about how receiving and handling Events in our ObservableObject from our new Publicist class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learningswift.brightdigit.com/combine-corelocation-publishers-delegates/"&gt;Creating Publishers from Delegates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using Function Reactive Programming to Transform Values&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Understanding flatMap and Built-In Publishers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Receiving and Handling Events in our ObservableObject
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;ObservableObject&lt;/code&gt; needs to accomplish a few things to update our SwiftUI while listening to our &lt;em&gt;CoreLocation&lt;/em&gt; publishers. First of all we need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the CoreLocation Manager&lt;/li&gt;
&lt;li&gt;Create our CoreLocation Publicist&lt;/li&gt;
&lt;li&gt;Connect the Publicist as the Delegate of the Manager&lt;/li&gt;
&lt;li&gt;Create our Authorization Status and Location Publishers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this in mind, here is how that looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notDetermined&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&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;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;publicist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerCombineDelegate&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&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;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&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;publicist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerPublicist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publicist&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publicist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publicist&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;authorizationPublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publicist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizationPublisher&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;locationPublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publicist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locationPublisher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we can actually deal with receiving and handling events from our Publishers. Firstly, let’s deal with the &lt;code&gt;CLAuthorizationStatus&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving and Handling Events with Sink and Assign
&lt;/h2&gt;

&lt;p&gt;As far the CLAuthorizationStatus, there are two things we need to do when the authorization status changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger Location Update when &lt;code&gt;CLAuthorizationStatus&lt;/code&gt; is valid&lt;/li&gt;
&lt;li&gt;Assign the &lt;code&gt;CLAuthorizationStatus&lt;/code&gt; to our &lt;code&gt;@Published CLAuthorizationStatus&lt;/code&gt; Property &lt;code&gt;authorizationStatus&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Sink For Calling Methods
&lt;/h3&gt;

&lt;p&gt;Let’s first deal with triggering location updates by creating a method to begin those updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notDetermined&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&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;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;beginUpdates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;authorizationStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&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;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorizedAlways&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorizedWhenInUse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startUpdatingLocation&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;p&gt;Our &lt;code&gt;beginUpdate&lt;/code&gt; method will take in the &lt;code&gt;CLAuthorizedStatus&lt;/code&gt; as it comes in from the &lt;code&gt;Publisher&lt;/code&gt;. As a result, &lt;strong&gt;if the status allows for location update then it calls &lt;code&gt;startUpdatingLocation&lt;/code&gt; on the &lt;code&gt;CLLocationManager&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With this in mind, let’s connect the &lt;code&gt;authorizationPublisher&lt;/code&gt; to the &lt;code&gt;beginUpdates&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&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;publicist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerPublicist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;authorizationPublisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publicist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizationPublisher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// trigger an update when authorization changes&lt;/span&gt;
    &lt;span class="n"&gt;authorizationPublisher&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;beginUpdates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, we are using &lt;code&gt;sink&lt;/code&gt; and passing a reference to our new method. &lt;code&gt;sink&lt;/code&gt; returns a &lt;code&gt;Cancellable&lt;/code&gt; which we’ll need to make sure is disposed properly. Therefore, we use &lt;code&gt;.store&lt;/code&gt; to make sure that &lt;code&gt;Cancellable&lt;/code&gt; is stored correctly in our &lt;code&gt;cancelables\&lt;/code&gt; &lt;code&gt;Array&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we should be correctly starting location updates when permission is granted. Next, let’s store the &lt;code&gt;CLAuthorizationStatus&lt;/code&gt; in our &lt;code&gt;@Published&lt;/code&gt; property so we can display it in our SwiftUI view.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving and Handling Events with Assign (in iOS 13 and iOS 14)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;One of the first things you learn as an iOS developer using UIKit is the importance of making UI updates on the main dispatch queue.&lt;/strong&gt; In other words, failure to do this results in incorrect UI updates or even crashing your app. Likewise, in SwiftUI, you need to specify UI updates on the main dispatch queue. Therefore we can use &lt;code&gt;receive&lt;/code&gt; to ensure updates are on the main &lt;code&gt;DispatchQueue&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="n"&gt;authorizationPublisher&lt;/span&gt;
        &lt;span class="c1"&gt;// since this is used in the UI,&lt;/span&gt;
        &lt;span class="c1"&gt;//  it needs to be on the main DispatchQueue&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As far as assigning we have a few options, we can stick with &lt;code&gt;sink&lt;/code&gt; to assign our value the published property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="n"&gt;authorizationPublisher&lt;/span&gt;
        &lt;span class="c1"&gt;// since this is used in the UI,&lt;/span&gt;
        &lt;span class="c1"&gt;//  it needs to be on the main DispatchQueue&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, we could simplify this with &lt;code&gt;assign&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="n"&gt;authorizationPublisher&lt;/span&gt;
        &lt;span class="c1"&gt;// since this is used in the UI,&lt;/span&gt;
        &lt;span class="c1"&gt;//  it needs to be on the main DispatchQueue&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="c1"&gt;// store the value in the authorizationStatus property&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;authorizationStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/combine/publisher/assign(to:)"&gt;This new assign available in all the new 2020 OSes (iOS 14, macOS 11, watchOS 7, etc…)&lt;/a&gt; allows us to assign the value directly to the publisher using the &amp;amp; (for an in-out parameter) and $ (for the publisher).&lt;/p&gt;

&lt;p&gt;Additionally no &lt;code&gt;Cancellable&lt;/code&gt; is returned and therefore not needed to be stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sink vs Assign when Receiving and Handling Events
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oTAvZG1_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/Combine-ing-the-Old-with-the-New.001-1024x204.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oTAvZG1_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/Combine-ing-the-Old-with-the-New.001-1024x204.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choosing the correct method can be difficult but here's some guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you are doing some additional logic besides just assigning a value, use &lt;code&gt;sink&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For just assigning a value, use &lt;code&gt;assign&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When assigning a value which is being used directly by the UI (i.e. UIKit View or SwiftUI View), use &lt;a href="https://developer.apple.com/documentation/combine/publisher/receive(on:options:)"&gt;&lt;code&gt;.receive(on: DispatchQueue.main)&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Make sure when using &lt;code&gt;sink&lt;/code&gt; or the &lt;a href="https://developer.apple.com/documentation/combine/publisher/assign(to:on:)"&gt;2019 version of &lt;code&gt;assign&lt;/code&gt;&lt;/a&gt; (i.e. &lt;code&gt;assign(to:on:)&lt;/code&gt;), save the resulting &lt;code&gt;Cancellable&lt;/code&gt; by &lt;a href="https://developer.apple.com/documentation/combine/anycancellable/store(in:)-6cr9i"&gt;using &lt;code&gt;.store&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;When there's more than one &lt;code&gt;AnyCancellable&lt;/code&gt; property, consider using a &lt;a href="https://developer.apple.com/documentation/combine/anycancellable/store(in:)-3hyxs"&gt;&lt;code&gt;Set&lt;/code&gt; or &lt;code&gt;Array&lt;/code&gt; for storing the &lt;code&gt;Cancellables&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next blog post, I'll cover some more advance functional programming techniques in Combine when we transform our &lt;code&gt;CLLocation&lt;/code&gt; to something more useful.&lt;/p&gt;

</description>
      <category>reactive</category>
      <category>swift</category>
      <category>swiftui</category>
      <category>ios</category>
    </item>
    <item>
      <title>Combine &amp; CoreLocation, Part 1 – Publishers &amp; Delegates</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Wed, 26 Aug 2020 21:03:38 +0000</pubDate>
      <link>https://dev.to/leogdion/combine-corelocation-part-1-publishers-delegates-164o</link>
      <guid>https://dev.to/leogdion/combine-corelocation-part-1-publishers-delegates-164o</guid>
      <description>&lt;p&gt;Most of the APIs from Apple come from an era of Objective-C and the Delegation Pattern. With this in mind, the challenge is figuring how to adapt for SwiftUI. Specifically we want to create Publishers from delegates using Combine.&lt;/p&gt;

&lt;p&gt;For instance, &lt;a href="https://heartwitch.app"&gt;my app Heartwitch is an Apple Watch app for live streamers&lt;/a&gt;. In this case, It uses HealthKit which implants the delegation pattern frequently. Additionally, I am using newer technologies such as Vapor 4, Independent Watch Apps, and most importantly SwiftUI.&lt;/p&gt;




&lt;p&gt;In this series of articles, I’d like to go into detail regarding the process of adapting an older API for Combine. Specifically &lt;strong&gt;we are going to be building a basic SwiftUI app which displays your latitude and longitude with CoreLocation.&lt;/strong&gt; This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating Publishers from Delegates&lt;/li&gt;
&lt;li&gt;Using Function Reactive Programming to Transform Values&lt;/li&gt;
&lt;li&gt;Understanding FlatMap and Built-In Publishers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this part, we'll be getting into how to create a &lt;code&gt;Protocol&lt;/code&gt; and &lt;code&gt;Class&lt;/code&gt; which will act as a go-between for the &lt;em&gt;Delegation Pattern&lt;/em&gt; and the &lt;em&gt;Reactive Functional Programming&lt;/em&gt; of &lt;strong&gt;SwiftUI&lt;/strong&gt; and &lt;strong&gt;Combine&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gonna Delegate Like It’s 2009
&lt;/h2&gt;

&lt;p&gt;For over a decade, Apple frequently used the Delegation Pattern for giving developers the ability to respond, update, and act in place of a UI object. This pattern has a plethora of benefits especially in Objective-C. However, with Swift and especially SwiftUI, this pattern becomes awkward.&lt;/p&gt;

&lt;p&gt;This is where it becomes necessary to make a delegate respond in such a way that SwiftUI can handle updates.&lt;/p&gt;

&lt;p&gt;With Apple’s older APIs, we typically see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;NSDelegate&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObjectProtocol&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;manager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doneWith&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyObject&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;manager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;grantedPermission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;NSManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSDelegate&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;requestAuthorization&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;doThing&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;In the case of &lt;strong&gt;CoreLocation&lt;/strong&gt; we see this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerDelegate&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObjectProtocol&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didUpdateLocations&lt;/span&gt; &lt;span class="nv"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didChangeAuthorization&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerDelegate&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;requestWhenInUseAuthorization&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;startUpdatingLocation&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;In other words, we’ll need to create Combine &lt;em&gt;Publishers&lt;/em&gt; which our &lt;code&gt;ObservableObject&lt;/code&gt; can listen or react to. Once the &lt;code&gt;ObservableObject&lt;/code&gt; reacts properly, then the &lt;code&gt;View&lt;/code&gt; will update accordingly. In the end, we should see this in our application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DTisA0dY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/CoreLocation-AppPreview-300x125.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DTisA0dY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/CoreLocation-AppPreview-300x125.jpg" alt="What we building"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we setup our publishers, let's scaffold our &lt;code&gt;View&lt;/code&gt; and &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  SwiftUI Scaffolding
&lt;/h2&gt;

&lt;p&gt;Let's first start by building our SwiftUI View. In this case, we'll be creating a SwiftUI view along with an &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="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;LocationView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// CLLocationManager is basically a singleton so an EnvironmentObject ObservableObject makes sense&lt;/span&gt;
  &lt;span class="kd"&gt;@EnvironmentObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;locationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// use our extension method to display a description of the status&lt;/span&gt;
      &lt;span class="kt"&gt;Text&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;locationObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorizationStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onTapGesture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locationObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// use Optional.map to hide the Text if there's no location&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locationObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This &lt;code&gt;LocationView&lt;/code&gt; will simply display one line with a description of the location with a line describing the &lt;code&gt;CLAuthorizationStatus&lt;/code&gt; using this extension:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CustomStringConvertible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;description&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="k"&gt;switch&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;authorizedAlways&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Always Authorized"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;authorizedWhenInUse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Authorized When In Use"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;denied&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Denied"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;notDetermined&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Not Determined"&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;restricted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Restricted"&lt;/span&gt;
    &lt;span class="kd"&gt;@unknown&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now let's go ahead and define our &lt;code&gt;ObservableObject&lt;/code&gt;, named &lt;code&gt;CoreLocationObject&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;CoreLocation&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;authorizationStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notDetermined&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nf"&gt;init&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;p&gt;Lastly, make sure that you set the &lt;code&gt;EnvironmentObject&lt;/code&gt; in your application using:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;LocationView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environmentObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CoreLocationObject&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, we have our scaffolding setup, let's plug-in &lt;em&gt;CoreLocation&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Extending Delegates into Combine Publishers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4cmyL9sZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/Combine-ing-the-Old-with-the-New-360iDev-August-2020.001-2-1024x538.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4cmyL9sZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/Combine-ing-the-Old-with-the-New-360iDev-August-2020.001-2-1024x538.png" alt="How to interface between the delegate and the ObservableObject"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the Delegation Pattern, the Delegate (in this case &lt;code&gt;CoreLocationManagerDelegate&lt;/code&gt;) will receive location updates. Therefore it is the ideal object to create publishers for our &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order for our &lt;code&gt;ObservableObject&lt;/code&gt; to react to &lt;em&gt;CoreLocation&lt;/em&gt; changes, the delegate will have to create &lt;em&gt;Publishers&lt;/em&gt; for us. With this in mind, I have extended to delegate to be a &lt;em&gt;&lt;strong&gt;Publicist&lt;/strong&gt;&lt;/em&gt;. That is to say the &lt;em&gt;Delegate&lt;/em&gt; will also be a &lt;em&gt;Publisher Factory&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerCombineDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerDelegate&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;authorizationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;locationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In the case of our application, we are displaying the authorization status of &lt;em&gt;Core Location&lt;/em&gt; as well as the latitude and longitude. Therefore, we only need two methods implemented for our publishers.&lt;/p&gt;

&lt;p&gt;Here is the implementation of our new protocol:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerPublicist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerCombineDelegate&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;authorizationSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;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;locationSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;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;authorizationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizationStatus&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&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;authorizationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&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;eraseToAnyPublisher&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;locationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didUpdateLocations&lt;/span&gt; &lt;span class="nv"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;locationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locations&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didFailWithError&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Implement to avoid crashes&lt;/span&gt;
    &lt;span class="c1"&gt;// Extra Credit: Create a publisher for errors :/&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didChangeAuthorization&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;authorizationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&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;Let’s breakdown how this class works.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Power of Type Erasing Publishers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Our Publicist doesn’t need to hold onto any values. In the end, it solely serves the purpose of transforming data from the &lt;code&gt;CoreLocationManager&lt;/code&gt; to the &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/strong&gt; For this reason, we’ll be using a &lt;code&gt;PassthroughSubject&lt;/code&gt; for the &lt;code&gt;CLLocation&lt;/code&gt; and &lt;code&gt;CLAuthorizationStatus&lt;/code&gt;. That is to say, &lt;code&gt;PassthroughSubject&lt;/code&gt; doesn't hold any values as they receive values but passes them on.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;PassthroughSubject&lt;/code&gt; properties in place, our delegate can send the values received from the delegate methods to the subjects.&lt;/p&gt;

&lt;p&gt;Creating our first &lt;em&gt;publisher&lt;/em&gt; for &lt;code&gt;CLLocation&lt;/code&gt; is fairly simple:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerPublicist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManagerCombineDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;locationSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;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;locationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&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;locationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didUpdateLocations&lt;/span&gt; &lt;span class="nv"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;locationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locations&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What’s important to realize is that we need to implement type erasure using &lt;code&gt;eraseToAnyPublisher&lt;/code&gt;. The introduction of SwiftUI and Combine included improvements to Swift. These improvement allow for powerful transformations which can result in fairly complex Generic Types. For instance our &lt;code&gt;authorizationPublisher&lt;/code&gt; has a return type &lt;code&gt;AnyPublisher&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;authorizationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizationStatus&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&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;authorizationSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&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;eraseToAnyPublisher&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;Without &lt;code&gt;eraseToAnyPublisher&lt;/code&gt;, the return type would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Merge&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;CompactMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Likewise with the &lt;code&gt;locationPublisher&lt;/code&gt;, the return type would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;CLLocation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In the end, this makes creating Protocols and Return Types fairly complex. &lt;strong&gt;As far as the &lt;code&gt;ObservableObject&lt;/code&gt; is concerned, it doesn’t care how the publisher is transformed but the result types returned.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Therefore our Protocol only needs a &lt;code&gt;AnyPublisher&lt;/code&gt; return type. In the end, we can both simplify and hide the method of functional transformation using &lt;code&gt;eraseToAnyPublisher&lt;/code&gt;. Likewise, the implementation calls &lt;code&gt;eraseToAnyPublisher&lt;/code&gt; to reduce the return type and match the Protocol's method signature.&lt;/p&gt;

&lt;p&gt;Now that we have figured out how to creating matching Publisher types, let’s transform &lt;code&gt;CLAuthorizationStatu&lt;/code&gt;s so it is usable within the view.&lt;/p&gt;
&lt;h2&gt;
  
  
  Transforming Authorization Status into a Publisher
&lt;/h2&gt;

&lt;p&gt;While our &lt;code&gt;locationSubject&lt;/code&gt; reflects the values from &lt;em&gt;CoreLocation&lt;/em&gt;, the &lt;code&gt;authorizationSubject&lt;/code&gt; will be out of sync from the reality of &lt;em&gt;CoreLocation&lt;/em&gt;’s status. For this reason, we’ll need to write some code include the initial status along with whatever the &lt;code&gt;PassthroughSubject&lt;/code&gt; receives.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;authorizationPublisher&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CLAuthorizationStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CLLocationManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizationStatus&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&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;authorizationSubject&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&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 &lt;code&gt;CoreLocationManagerDelegate&lt;/code&gt; sends updates to &lt;code&gt;authorizationStatus&lt;/code&gt;, we need to have access to the initial status via &lt;code&gt;CLLocationManager.authorizedStatus&lt;/code&gt;. Luckily, Combine includes a built-in &lt;em&gt;Publisher&lt;/em&gt; for single values using &lt;code&gt;Just&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Just&lt;/code&gt; gives us the initial value published however we need to include the remaining published values from our &lt;code&gt;PassthroughSubject&lt;/code&gt;. For this reason, we can use &lt;code&gt;merge&lt;/code&gt; to join the intial value with the result from the our &lt;code&gt;authorizationSubject&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gmTe1bII--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/optimized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gmTe1bII--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2020/08/optimized.gif" alt="How to transform CLAuthorizationStatus into something useful"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have the publisher factories setup now!&lt;/p&gt;

&lt;p&gt;Interested in learning more about Combine, check out my podcast episode with Donny Wals:&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/practical-combine-with-donny-wals"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Practical Combine with Donny Wals&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-practical-combine-with-donny-wals" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-practical-combine-with-donny-wals" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-practical-combine-with-donny-wals" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-practical-combine-with-donny-wals" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-practical-combine-with-donny-wals"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/practical-combine-with-donny-wals"&gt;
        &lt;img id="episode-profile-image" alt="Practical Combine with Donny Wals" width="420" height="420" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;In our next part in this series, we'll learn how to use this implementation in our &lt;code&gt;ObservableObject&lt;/code&gt; &lt;code&gt;CoreLocationObject&lt;/code&gt;. &lt;strong&gt;Specifically, we'll be getting into power of function programming within Reactive Functional Programming.&lt;/strong&gt; Enjoy!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>swiftui</category>
    </item>
    <item>
      <title>flatMap, Double Optionals, and Functional Programming</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Thu, 23 Apr 2020 11:50:08 +0000</pubDate>
      <link>https://dev.to/leogdion/flatmap-double-optionals-and-functional-programming-1nh4</link>
      <guid>https://dev.to/leogdion/flatmap-double-optionals-and-functional-programming-1nh4</guid>
      <description>&lt;p&gt;A while ago &lt;a href="https://learningswift.brightdigit.com/understanding-optionals-in-swift/"&gt;I did an article on the basics of &lt;strong&gt;Optionals&lt;/strong&gt;&lt;/a&gt; and how they work in Swift. However, it seems there's some confusion as to how one particular method works in Swift when it comes to a collection of &lt;strong&gt;Optionals&lt;/strong&gt;: &lt;em&gt;flatMap&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;With all the talk regarding &lt;em&gt;flattening the curve&lt;/em&gt;, today I want to explain exactly what it means to flatten in the context of functional programming. Additionally, it not only can be used on &lt;strong&gt;Arrays&lt;/strong&gt; but single &lt;strong&gt;Optionals&lt;/strong&gt; as well. In the end, using them correctly will make your code easier to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  flatMap vs map and Generic
&lt;/h2&gt;

&lt;p&gt;Before we dive into what &lt;em&gt;&lt;strong&gt;flatMap&lt;/strong&gt;&lt;/em&gt; does, let's talk about &lt;strong&gt;what flatten actually means&lt;/strong&gt;. Most importantly, &lt;em&gt;flatMap&lt;/em&gt; is typically a &lt;em&gt;map&lt;/em&gt; coupled with a &lt;em&gt;flatten&lt;/em&gt; operation. The flatten operation typically is used in the context of &lt;strong&gt;Generics&lt;/strong&gt;, such as &lt;strong&gt;Arrays&lt;/strong&gt;, &lt;strong&gt;Promises&lt;/strong&gt;, &lt;strong&gt;Publishers&lt;/strong&gt;, and even &lt;strong&gt;Optionals&lt;/strong&gt; (&lt;em&gt;remember Optionals are Generic enums&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Let's create our own Generic to show how this would work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Foo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's a simple Generic &lt;code&gt;Foo&lt;/code&gt; which contains a value. Therefore, let's add a simple map function in case the developer wants to convert the value into something else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Value&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="kt"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;)&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;Foo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Foo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;output&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;Now we have simple map method which works similar to others, where the developer can convert the &lt;code&gt;Foo&lt;/code&gt; into some other type. For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;firstItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.0&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;secondItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;firstItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, we have a &lt;code&gt;Foo&amp;lt;Double&amp;gt;&lt;/code&gt; which is converted into a &lt;code&gt;Foo&amp;lt;String&amp;gt;&lt;/code&gt; using our new map function.&lt;/p&gt;

&lt;p&gt;However there are instances where this can cause issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Arrays of Arrays
&lt;/h3&gt;

&lt;p&gt;The simplest case where map doesn't quite do what you want would be when you need a flat list. For instance, let's say you want to get a flat list of books from their authors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;...&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;let&lt;/span&gt; &lt;span class="nv"&gt;books&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 you have a list of authors and their books in JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Franz Kafka"&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="s2"&gt;"Stories"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Trial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Castle"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Fyodor Dostoevsky"&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="s2"&gt;"Crime and Punishment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Idiot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Possessed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Brothers Karamazov"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Leo Tolstoy"&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="s2"&gt;"War and Peace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Anna Karenina"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Death of Ivan Ilyich"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"William Shakespeare"&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="s2"&gt;"Hamlet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"King Lear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Othello"&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="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;Unfortunately, map would only return an &lt;strong&gt;Array of an Array&lt;/strong&gt; or &lt;strong&gt;Jagged Array&lt;/strong&gt; of books (i.e. &lt;code&gt;[[String]]&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;authors&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As a result, we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Stories"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"The Trial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"The Castle"&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="s2"&gt;"Crime and Punishment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Idiot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Possessed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"The Brothers Karamazov"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, this is where a &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; would be useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;authors&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;books&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, rather than returning an Array of Arrays, &lt;em&gt;flatMap&lt;/em&gt; automatically flattens the result. Not only does this work with Arrays but other &lt;strong&gt;Generics&lt;/strong&gt; as well. A great example of this is in use with asynchronous methods.&lt;/p&gt;

&lt;p&gt;If you are interested in learning more about how SwiftNIO and Google Futures does this with Promises and Futures, check out my &lt;a href="https://learningswift.brightdigit.com/asynchronous-multi-threaded-parallel-world-of-swift/"&gt;article on asynchronous programming here.&lt;/a&gt;  Additionally Combine, which is frequently used with SwiftUI, contains a &lt;a href="https://developer.apple.com/documentation/combine/publisher/3204718-map"&gt;map&lt;/a&gt; and &lt;a href="https://developer.apple.com/documentation/combine/publisher/3204712-flatmap"&gt;flatMap&lt;/a&gt; for its Publishers as well.&lt;/p&gt;

&lt;p&gt;Besides Arrays, Promises, and Combine Publishers, there was one other Generic we are forgetting to cover which often can cause issues. If you have run into the elusive &lt;code&gt;Type??&lt;/code&gt; value then you have probably run into an instance where &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; should be used on &lt;strong&gt;Optionals&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  flatMap and the elusive Double Optional??
&lt;/h2&gt;

&lt;p&gt;So let's say we have a generic function which returns an optional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;maybe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&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;T&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;value&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then you've created a optional value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;optionalValue&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;=&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, you decide to call that function which returns an optional on the option value and you end up with something that makes very little sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;optionalOptional&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;=&lt;/span&gt; &lt;span class="nf"&gt;maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What is an &lt;code&gt;Int??&lt;/code&gt;...?&lt;/p&gt;

&lt;p&gt;As stated earlier &lt;strong&gt;an Optional is really another Generic type.&lt;/strong&gt; Here's a small snippet of the Generic Enumeration behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Wrapped&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;none&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Wrapped&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;As you can see the '?' is simply syntactic sugar. So for instance an &lt;code&gt;Int?&lt;/code&gt; is really an &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt;. Therefore, we can surmise that an &lt;code&gt;Int??&lt;/code&gt; is really a &lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Therefore, we need to make sure that our result is flattened in order to use it. Luckily, &lt;strong&gt;Optional&lt;/strong&gt; provides a &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; function as well. For this reason, we can use &lt;a href="https://developer.apple.com/documentation/swift/optional/1540500-flatmap"&gt;&lt;code&gt;Optional.flatMap&lt;/code&gt;&lt;/a&gt; to fix our result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;betterOptionalValue&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;=&lt;/span&gt; &lt;span class="n"&gt;optionalValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;maybe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By using &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt;, it flattens the result to return a &lt;em&gt;single&lt;/em&gt; &lt;strong&gt;Optional&lt;/strong&gt;. It's important to note, that &lt;code&gt;optionalValue&lt;/code&gt; does not contain the &lt;code&gt;?&lt;/code&gt; suffix since we want to call &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; on &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt; as opposed to Int. Likewise, &lt;strong&gt;Optional&lt;/strong&gt; also contains a map function for when your method will return a non-optional value and does not require flattening.&lt;/p&gt;

&lt;h3&gt;
  
  
  flatMap, parsing, and conversion
&lt;/h3&gt;

&lt;p&gt;There are a few use cases where &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; on an &lt;strong&gt;Optional&lt;/strong&gt; are useful. For instance, when you are parsing a value, there are cases where you wish to throw an error depending whether the value is invalid or missing (i.e. &lt;code&gt;nil&lt;/code&gt;). However in some instances, you don't care whether the value is invalid or &lt;code&gt;nil&lt;/code&gt; and want to just return &lt;code&gt;nil&lt;/code&gt; if it fails. In this case, &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; fits perfectly well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;rawValue&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;RawType&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;ParsedType&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;parsedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optionalRawValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For instance, parsing UUID from a String, rather than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;uuid&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UUID&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;uuidString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"VCS_UUID"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;uuidString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uuidString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;... we can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"VCS_UUID"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;uuidString&lt;/span&gt;&lt;span class="p"&gt;:))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Besides parsing, I've used &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; in instances where I need to convert a successful &lt;code&gt;Result&lt;/code&gt; or value to a SwiftUI &lt;code&gt;View&lt;/code&gt; as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;iconImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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="n"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderingMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;template&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;In this case if the &lt;code&gt;self&lt;/code&gt; &lt;code&gt;View&lt;/code&gt; contains an &lt;code&gt;icon&lt;/code&gt; with the case &lt;code&gt;image&lt;/code&gt; then use the &lt;code&gt;name&lt;/code&gt; and create templated &lt;code&gt;Image&lt;/code&gt; for the &lt;code&gt;View&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While there are instances where &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; is useful, more often than not you may just wish to filter the &lt;strong&gt;Optional&lt;/strong&gt; results from a map operation. This is where &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  flatMap vs compactMap
&lt;/h2&gt;

&lt;p&gt;In many instances, you probably want simply remove Optionals from your Array or having a map return only non-Optional values. Before Swift 4.1, there was only one method for doing this as well as the traditional &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; mentioned previously. Unfortunately as stated in &lt;a href="https://github.com/apple/swift-evolution/blob/master/proposals/0187-introduce-filtermap.md"&gt;the implemented proposal,&lt;/a&gt; this caused much confusion. Therefore &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; was added in Swift 4.1.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; concerns the returning of a flat Array of values, &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; is specifically for instances where you need to make sure the Array returned contains no Optional values. In effect, &lt;strong&gt;if the closure for each item can return multiple items then a flatMap is right; otherwise if the closure can return either no items (i.e. nil) or one then compactMap makes the most sense.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So for example, if we have &lt;code&gt;Node&lt;/code&gt; struct and an Array of optional Nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;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;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Value&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;children&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Value&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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;items&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;?]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Therefore, let's see what happens when we use a combination of &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; in various ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// returns an array with no Optionals&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// returns and array of array of Nodes&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;arrayArray&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// assumes same as previous compactMap and issues a warning&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;arrayArrayWithWarning&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// returns flat array of Nodes from children&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flatArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// returns flat array of Nodes from children as well&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flatCompactArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Most importantly, &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; is not supposed to return a &lt;code&gt;nil&lt;/code&gt; (otherwise the compiler assumes it's &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; and issues a warning). Therefore, you can either use &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html#ID72"&gt;the nil-coalesce operator&lt;/a&gt; to return an empty Array or use &lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; beforehand to ensure there will never be &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  flatMap and flattening the Optionals and Generics
&lt;/h2&gt;

&lt;p&gt;In this article, you've learned a few key points with regards to &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; and its relationship to &lt;strong&gt;Generics&lt;/strong&gt; and specifically &lt;strong&gt;Optionals&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The term &lt;strong&gt;&lt;em&gt;flatten&lt;/em&gt;&lt;/strong&gt; in functional programming means to remove a secondary generic into a one-dimensional result such as returning a &lt;code&gt;Value?&lt;/code&gt; rather than &lt;code&gt;Value??&lt;/code&gt; or &lt;code&gt;[Value]&lt;/code&gt; rather than [&lt;code&gt;[Value]]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; is to be used when you have an Array of Arrays and wish to flatten those Collections into a simple one-dimensional Array&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; when you are returning a result of the same &lt;strong&gt;Generic&lt;/strong&gt; type as opposed to map when you are just returning a value such as a &lt;strong&gt;Promise&lt;/strong&gt;, &lt;strong&gt;Future&lt;/strong&gt;, or &lt;strong&gt;Combine&lt;/strong&gt; &lt;strong&gt;Publisher&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; is important for &lt;strong&gt;Optionals&lt;/strong&gt; in removing &lt;strong&gt;Double Optionals&lt;/strong&gt; (i.e. &lt;code&gt;**Type??**&lt;/code&gt;) from your code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;flatMap&lt;/strong&gt; is also useful for &lt;strong&gt;Optional&lt;/strong&gt; when you are mapping an &lt;strong&gt;Optional&lt;/strong&gt; value and &lt;strong&gt;don't need to distinguish between a nil or invalid input value&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;compactMap&lt;/em&gt;&lt;/strong&gt; is specifically for the removing nil results from an one-dimensional array&lt;/li&gt;
&lt;li&gt;If a &lt;strong&gt;&lt;em&gt;flatMap&lt;/em&gt;&lt;/strong&gt; closure can return nil, return an empty Array instead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out if you have any additional questions &lt;a href="https://twitter.com/leogdion"&gt;on Twitter &lt;strong&gt;@leogdion&lt;/strong&gt;&lt;/a&gt; or signup for the newsletter below to get the latest tutorials and guides on Swift development.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>What You Should Know About iOS Software Architecture</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Mon, 06 Apr 2020 15:39:36 +0000</pubDate>
      <link>https://dev.to/leogdion/what-you-should-know-about-ios-software-architecture-2f2</link>
      <guid>https://dev.to/leogdion/what-you-should-know-about-ios-software-architecture-2f2</guid>
      <description>&lt;p&gt;You’ve made the decision to build your own iOS app. Therefore, you’ve started out with an idea based on a customer need. Also how the app will meet that need and what it will look like. It’s at this point you should think about iOS software architecture.  &lt;/p&gt;

&lt;p&gt;Software architecture is the term we use to describe how major components of an app work together. The structure and design of modern software are usually too complex to consider. Therefore, we use the term ‘architecture’ as an abstraction. In practice, ‘software architecture’ means “the parts of the app we need to get right.”&lt;/p&gt;

&lt;p&gt;The reason well-planned architecture for your app is critical is that by investing time in planning, it pays off over time. In the end, you create a shared understanding between you and your developers. This includes how they structure and design the app. As a result, you are saving you time and money.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/TQpRYibmyvQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this post, I cover three essential concepts for good iOS software architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patterns &amp;amp; Practices&lt;/li&gt;
&lt;li&gt;Code Modularization&lt;/li&gt;
&lt;li&gt;Code Quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll be explaining a bit about each, how you can put them in place for your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS Software Architecture Patterns
&lt;/h2&gt;

&lt;p&gt;Choosing a certain architecture for your iOS app determines the design of different aspects of your software. Within that, it also determines what kind of design patterns you will want to use. A Pattern in the context of software is a common response to a recurring problem. It uses a common language to outline the elements needed to solve a software challenge.&lt;/p&gt;

&lt;p&gt;Patterns are particularly useful when working with a large team of developers. They can make your developers substantially more efficient by using a refined approach to solving problems. Patterns ensure changes to the code are consistent and reduce risk for major changes.&lt;/p&gt;

&lt;p&gt;Good use of Architecture Patterns makes it easy for developers to understand the software. In the end that makes it easy to change it. This means new features can be delivered faster, with fewer bugs, and therefore easier fixes.&lt;/p&gt;

&lt;p&gt;There are a few architectural patterns that are very useful when making iOS apps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i05x6Hx9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/03/EAS.42-Slides.001-scaled.jpeg%3Ffit%3D640%252C360%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i05x6Hx9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/03/EAS.42-Slides.001-scaled.jpeg%3Ffit%3D640%252C360%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Delegation and MVC with iOS Software Architecture
&lt;/h3&gt;

&lt;p&gt;Delegation is a pattern we use in iOS user interface (UI) development for displaying tables of information in an app. The Model-View-Controller (MVC) pattern uses Delegation. Additionally, MVC is the most popular iOS Software architectural pattern for developing Apple apps. This is how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user performs an action within the user interface (ie &lt;strong&gt;View&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;View passes it to the &lt;strong&gt;Controller&lt;/strong&gt; to deal with.&lt;/li&gt;
&lt;li&gt;The Controller makes decisions about what to do with the action it's been given. If needed, it makes changes to the state of the &lt;strong&gt;Model&lt;/strong&gt;, which will change its data values in response.&lt;/li&gt;
&lt;li&gt;The Controller then sees these new values and sets them for View.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Delegation allows you to control how the Controller provides both the data and the way that data needs to be displayed to View in the final step. This makes it easy to break apart the functionality of the code to display table information to your user the way you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protocol-Oriented Programming
&lt;/h3&gt;

&lt;p&gt;This is fundamental to developing any app written in Swift (ie all native apps for iOS). Protocols allow you to group together and separate functionality. Additionally it shows how data and their objects work together.&lt;/p&gt;

&lt;p&gt;Protocols are useful tools for creating functionality for your app. Instead of building a whole new object (which you might with other kinds of architecture), you add different protocols until your objects can do what you want. Protocol-oriented programming means using an architecture where you design your app around protocols. This makes it easy to test the different parts of your app and &lt;a href="https://brightdigit.com/blog/2020/01/06/avoid-ios-app-failure-with-tdd/"&gt;use Test-Driven Development&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functional Programming
&lt;/h3&gt;

&lt;p&gt;Functional programming is the idea of having your app work based around information supplied to it and rules it must follow. What this means is you want the app to react to what your user is doing. In contrast other kinds of programming styles, such as Imperative which follow a set of instructions, this can be a challenge. For instance, if there are multiple data sources and multiple views. The result is an app that can adapt to your user’s behavior, which is always a desirable trait in a well-designed app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rKgeM28M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/03/EAS.42-Slides.002-1-scaled.jpeg%3Ffit%3D640%252C360%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rKgeM28M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/03/EAS.42-Slides.002-1-scaled.jpeg%3Ffit%3D640%252C360%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactive Programming in iOS Software Architecture
&lt;/h3&gt;

&lt;p&gt;This pattern has become popular with the introduction of &lt;a href="https://brightdigit.com/blog/2020/02/04/swiftui-everything-is-possible-if-you-think-like-apple/"&gt;SwiftUI&lt;/a&gt;, which encourages developers to use functional reactive programming. For this reason, Apple introduced &lt;a href="https://developer.apple.com/documentation/combine"&gt;the Combine framework&lt;/a&gt; and the Subscriber-Publisher model. Specifically, this allows you to sort and filter values into your UI.  Additionally, it's also used with Model-View-ViewModel, which removes the Controller in the MVC pattern mentioned above. With Model-View-Model, the Controller is replaced with a ViewModel. Conversely, the ViewModel automates how the Model can be rendered directly into the View by making changes to the Model data and reacting accordingly. This is useful for iOS apps that need to use a resource library that isn’t written in Swift. It allows you to bridge from another programming language into Swift.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/wwdc-2019-swift-ui-with-jason-anderson"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;WWDC 2019 - Swift UI with Jason Anderson&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-wwdc-2019-swift-ui-with-jason-anderson" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-wwdc-2019-swift-ui-with-jason-anderson" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-wwdc-2019-swift-ui-with-jason-anderson" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-wwdc-2019-swift-ui-with-jason-anderson" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-wwdc-2019-swift-ui-with-jason-anderson"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/wwdc-2019-swift-ui-with-jason-anderson"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="WWDC 2019 - Swift UI with Jason Anderson" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why Code Modularity Matters in iOS Software Architecture
&lt;/h2&gt;

&lt;p&gt;Another key component of great architecture is modularity.&lt;/p&gt;

&lt;p&gt;Modularity is the idea that different parts of your app should be able to work independently of each other. As a result, this makes it easier to both test and reuse pieces of code in different parts of your app. Additionally, makes it easy to use the same piece of code for different platforms, so your iOS code could work on macOS too.&lt;/p&gt;

&lt;p&gt;There are three ways I recommend for creating modularity in iOS app development:&lt;/p&gt;

&lt;h3&gt;
  
  
  Framework Targets
&lt;/h3&gt;

&lt;p&gt;In Xcode (the development environment for macOS), Framework Targets are a way to easily move your app’s code from the testing environment where it was built to the production environment your users can see. Ordinarily, you have to swap out all the URLs and APIs from the testing version of your app to the production one. With Framework Targets, this is done automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Projects and Workspaces
&lt;/h3&gt;

&lt;p&gt;You have a specific piece of code that doesn’t fit into an existing framework but might be used in many apps. A way to deal with this is to have more than one project and workspace. This allows you to organize pieces of code like this and show how they are related to different development projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swift Packages
&lt;/h3&gt;

&lt;p&gt;The newest and simplest way to achieve modularity. Although limited to Swift and not compatible with older apps, Apple is encouraging a shift toward using only Swift for new apps. As a result, this means Packages will likely become the default to create modularity for iOS apps. If you are interested in learning how to use Continuous Integration with your Swift Packages, &lt;a href="https://learningswift.brightdigit.com/swift-package-continuous-integration-guide/"&gt;check out our developer article here.&lt;/a&gt;&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/modularizing-in-xcode-with-abbey-jackson"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Modularizing in Xcode with Abbey Jackson&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-modularizing-in-xcode-with-abbey-jackson" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-modularizing-in-xcode-with-abbey-jackson" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-modularizing-in-xcode-with-abbey-jackson" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-modularizing-in-xcode-with-abbey-jackson" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-modularizing-in-xcode-with-abbey-jackson"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/modularizing-in-xcode-with-abbey-jackson"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="Modularizing in Xcode with Abbey Jackson" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why Maintaining Code Quality Matters
&lt;/h2&gt;

&lt;p&gt;This isn’t so much about app architecture as it is the ability of other to maintain your code. If you have high-quality code, it will make development faster, easier, and cheaper.&lt;/p&gt;

&lt;p&gt;There are a few are great ways to ensure high-quality code:&lt;/p&gt;

&lt;h3&gt;
  
  
  Test-Driven Development
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://brightdigit.com/blog/2020/01/06/avoid-ios-app-failure-with-tdd/"&gt;I recently did a piece about Test-Driven Development (TDD), which you can find here&lt;/a&gt;. Committing to doing good testing and setting up a good testing environment is one of the most powerful things you can do to make your code top-notch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure Good Code Coverage
&lt;/h3&gt;

&lt;p&gt;Code coverage, measured as a percentage, refers to how much of your app’s code is executed during testing. A high degree of code coverage indicates a low number of possible undetected bugs in your app. This is a great measurement for determining code quality, although you shouldn't be too strict about it. While it’s obviously great if you reach 100% coverage, it might come at a cost when there are more important things you could be doing to serve your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;In software development, there are two kinds of complexity we want to observe and measure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cyclomatic Complexity&lt;/strong&gt; – this metric looks at the number of linear paths it is possible for data to take through your app’s source code. While there are going to be times when it's necessary to have many paths, you generally want to limit this kind of complexity. The reason is that more paths mean needing more test cases to make sure they all work, and more paths mean more opportunities for bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cognitive Complexity&lt;/strong&gt; – this metric simply refers to how easy it is for people to understand your code. Easy-to-understand code is always going to be easier to maintain. This is especially true if the person who wrote the code and the person maintaining it are different people.&lt;/p&gt;

&lt;p&gt;Overall, keeping your complexity low by limiting file and function length means adding features and fixing bugs takes less effort.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/managing-code-quality-with-anne-cahalan"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Managing Code Quality with Anne Cahalan&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-managing-code-quality-with-anne-cahalan" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-managing-code-quality-with-anne-cahalan" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-managing-code-quality-with-anne-cahalan" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-managing-code-quality-with-anne-cahalan" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-managing-code-quality-with-anne-cahalan"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/managing-code-quality-with-anne-cahalan"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="Managing Code Quality with Anne Cahalan" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Code Reviews
&lt;/h3&gt;

&lt;p&gt;A code review is when someone other than the code’s creator reads the code, looking for errors or anything unclear. While simple to do, this often gets missed because it takes time to sit down and review code someone else has written —time you might feel you don't have. Having someone review what you’ve written is a great way of spotting mistakes and ensuring better-quality code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Integration
&lt;/h3&gt;

&lt;p&gt;This is something &lt;a href="https://brightdigit.com/blog/2020/03/02/ios-continuous-integration-avoid-merge-hell/"&gt;I’ve written about recently, explaining what Continuous Integration (CI) is and why it’s important.&lt;/a&gt; If you are able to deploy the code frequently, it means you can deliver features more rapidly. Additionally, if there are problems or bugs, you will discover them faster and will be easier to fix. Therefore, using CI is a great way to shorten the time it takes to get feedback from your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Components of Good iOS Software Architecture
&lt;/h2&gt;

&lt;p&gt;By thoughtfully choosing an architecture for your app, using effective patterns and modularity, as well following good code quality practices, you will find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bug fixes become easier;&lt;/li&gt;
&lt;li&gt;adding new features becomes straightforward;&lt;/li&gt;
&lt;li&gt;your app becomes easier to test and maintain; and,&lt;/li&gt;
&lt;li&gt;your developers will have an easier time understanding the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe these are things we should all try to observe. You’ll find it not only improves the morale of your developers, but it will also save you a lot of time and money in the long term.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Want more about iOS software architecture on how to create better iOS apps?
&lt;/h2&gt;

&lt;p&gt;If you want to learn ways to save time and money and make smart decisions about developing an iOS app for your business, I invite you to &lt;a href="https://brightdigit.com/subscribe/"&gt;sign up for my newsletter&lt;/a&gt;. I will let you know when I put out new content like this and if there are important things you should know.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>development</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Productivity Apps for Developers (and Everyone Else)</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Fri, 13 Mar 2020 20:15:26 +0000</pubDate>
      <link>https://dev.to/leogdion/productivity-apps-for-developers-and-everyone-else-1dml</link>
      <guid>https://dev.to/leogdion/productivity-apps-for-developers-and-everyone-else-1dml</guid>
      <description>&lt;p&gt;As a remote software developer who’s transitioned to many roles as a self-employed freelancer, it’s important to keep a set of great software tools. Most importantly tools which help me optimize rather than distract me. Therefore, here’s a list of productivity apps and services I use to keep my workflow going. In contrast, these are not development tools necessarily but rather software which helps with other &lt;em&gt;office&lt;/em&gt; work which I do. To begin with, you’ll need an easy way to install, run, and track your application as well as your computer’s disk space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--srWvaYGF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/patrick-lindenberg-1iVKwElWrPA-unsplash-e1564280406506-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--srWvaYGF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/patrick-lindenberg-1iVKwElWrPA-unsplash-e1564280406506-1024x512.jpg" alt="Managing Your Disk Space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Productivity Apps and Disk
&lt;/h2&gt;

&lt;p&gt;For many developers, we live in the command line. Therefore, using a package manager is a great way to install apps without the need to load a distracting web page. For instance, on Linux there’s &lt;a href="https://wiki.debian.org/Apt#How%5C_to%5C_use.3F"&gt;apt&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Yum%5C_(software)"&gt;yum&lt;/a&gt;; Windows has &lt;a href="https://chocolatey.org"&gt;Chocolatey&lt;/a&gt; and on the Mac is &lt;a href="https://brew.sh"&gt;Homebrew&lt;/a&gt; which is what I use. Altogether, this allows you also to track what you have installed especially using &lt;a href="https://github.com/Homebrew/homebrew-bundle"&gt;Homebrew Bundle&lt;/a&gt;. Outside of the Mac App Store, Homebrew is a great way to install and manage your productivity apps.&lt;/p&gt;

&lt;p&gt;Secondly, one of the first apps I install on my Mac is &lt;a href="https://www.alfredapp.com/?ref=okproductive"&gt;Alfred&lt;/a&gt;. In essence, Alfred not only is superior to the Spotlight search but also offers a plethoria of different services you can integrate with. Thereupon, you can simply map a hot key to that service and it’ll allow you to search for apps, contacts, do math problems, or give you directions.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/okproductivepodcast/016-productivity-apps-episode"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;016. Productivity Apps Episode&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/okproductivepodcast"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        OK Productive  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-016-productivity-apps-episode" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-016-productivity-apps-episode" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-016-productivity-apps-episode" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-016-productivity-apps-episode" alt="OK Productive" src="https://res.cloudinary.com/practicaldev/image/fetch/s--uQxlgLFn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--EhEKRwUW--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/80/45d8d923-d251-48d2-9498-0156ce68dadf.png"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-016-productivity-apps-episode"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/okproductivepodcast/016-productivity-apps-episode"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="016. Productivity Apps Episode" src="https://res.cloudinary.com/practicaldev/image/fetch/s--f6qRxKo8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s---i_5mMAd--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/80/45d8d923-d251-48d2-9498-0156ce68dadf.png"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;While installing all of your productivity apps, you may need to watch your disk space. That’s where &lt;a href="http://cl.ly/ehYa?ref=empowerapps"&gt;Daisydisk&lt;/a&gt; comes in. In short, DaisyDisk gives you great visualization of how your disk space is used as well as how to cleanup your disk. In contrast to tracking your disk space, let’s talk about a real productivity challenge - tracking your time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yekfnzLU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/eric-rothermel-FoKO4DpXamQ-unsplash-e1564280204228-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yekfnzLU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/eric-rothermel-FoKO4DpXamQ-unsplash-e1564280204228-1024x512.jpg" alt="Managing Your Time"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Tracking and Scheduling Apps
&lt;/h2&gt;

&lt;p&gt;With many of my clients and partners, I need to schedule meetings and track my time. Specifically, there’s one app I use for arranging meetings - that is &lt;a href="https://doodle.com/"&gt;Doodle&lt;/a&gt;. That is to say, Doodle is a platform which allows for easy polling and basic surveys including scheduling. For instance, I can easily share a poll which asks participants the best time to meet from a set of times available. Once votes are placed, I can send them an invite easily.&lt;/p&gt;

&lt;p&gt;As far as tracking my time, I currently use &lt;a href="https://toggl.com/"&gt;Toggl&lt;/a&gt;. Generally speaking, Toggl doesn’t come with a lot of bells and whistles, however its open API and simplicity make it ideal for reporting and tracking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Eu6ldqK0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/glenn-carstens-peters-RLw-UC03Gwc-unsplash-e1564280558255-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eu6ldqK0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/glenn-carstens-peters-RLw-UC03Gwc-unsplash-e1564280558255-1024x512.jpg" alt="Tracking Your Todo List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reminders and Todo List Productivity Apps
&lt;/h2&gt;

&lt;p&gt;For tracking my tasks, currently I use a combination of weekly Spreadsheets and &lt;a href="https://todoist.com/"&gt;Todoist.&lt;/a&gt; In particular, Todoist offers the ability to share tasks easily with others whether it’s a podcast episode I am working on or a shopping list with my wife. Additionally, I can easily group tasks as well set priorities and due dates.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/okproductivepodcast/007-list-2-top-apps-episode"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;007. List #2 – Top Apps Episode&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/okproductivepodcast"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        OK Productive  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-007-list-2-top-apps-episode" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-007-list-2-top-apps-episode" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-007-list-2-top-apps-episode" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-007-list-2-top-apps-episode" alt="OK Productive" src="https://res.cloudinary.com/practicaldev/image/fetch/s--uQxlgLFn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--EhEKRwUW--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/80/45d8d923-d251-48d2-9498-0156ce68dadf.png"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-007-list-2-top-apps-episode"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/okproductivepodcast/007-list-2-top-apps-episode"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="007. List #2 – Top Apps Episode" src="https://res.cloudinary.com/practicaldev/image/fetch/s--f6qRxKo8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s---i_5mMAd--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/80/45d8d923-d251-48d2-9498-0156ce68dadf.png"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Conversely I also use spreadsheets to track my weekly items. (I use Numbers - of course you can use Excel or Google Sheets) As an example I simply add the name of the task (&lt;em&gt;Write a Development Tools&lt;/em&gt;) and assign a priority and desire between 0-100 (99) as well as approximate minutes (3 hours?). Lastly, I sort by priority and desire and then based on my availability, work on the top items for that week. Then, each week I copy the sheet into a new one, delete the completed items, copy the old priorities over, set new priorities for the week, and repeat.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIQcCioA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/neonbrand-Ak5c5VTch5E-unsplash-e1564280607730-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIQcCioA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/neonbrand-Ak5c5VTch5E-unsplash-e1564280607730-1024x512.jpg" alt="Writing and Notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes and Writing Productivity Apps
&lt;/h2&gt;

&lt;p&gt;For developers, MarkDown has become the most convenient way to organize as well as create documents. If you are not familiar with Markdown, I highly recommend taking 30 minutes and becoming familiar with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet"&gt;Adam Pritchard’s Quick Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.github.com/features/mastering-markdown/"&gt;Github’s Mastering Markdown&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://daringfireball.net/projects/markdown/"&gt;John Gruber’s Markdown Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether it’s communications, documentation, blogging, or note taking, Markdown is a great way to keep your text organized and formatted. Therefore many note taking apps use Markdown, including the one I use - &lt;a href="https://bear.app/?ref=okproductive"&gt;Bear&lt;/a&gt;. To point out, Bear works only on iOS and Mac and a web front-end is in the works. However, Bear’s strong point is its simplicity, versatility as well as UI.&lt;/p&gt;

&lt;p&gt;Conversely, if you prefer to use something besides Bear or any Markdown specific app, there’s always Google Docs. Most importantly, since Google Docs is so widely accepted, sharing documents has become easy and painless. For instance, I’ll explicitly use Google Docs for show notes and any long form writing which needs to be shared.&lt;/p&gt;

&lt;p&gt;For other long-form writing, I am a big fan of &lt;a href="https://ulysses.app/?ref=empowerapps"&gt;Ulysses&lt;/a&gt;. Just as with Bear, &lt;a href="https://ulysses.app/?ref=empowerapps"&gt;Ulysses&lt;/a&gt; is specifically for macOS and iOS, however its purpose is explicitly long-form distraction-free writing. Most importantly, it has a great UI and has helped keep my writing organized and flow easily. Additionally, it can export to several formats such as Word Doc, HTML, PDF, Wordpress, Medium, and more. Besides my writing, I also record podcasts and do video as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---mpprct3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/06/neil-godding-179009-unsplash-687-e1560428361178-1024x512.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---mpprct3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/06/neil-godding-179009-unsplash-687-e1560428361178-1024x512.jpeg" alt="Recording Multimedia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creative Apps
&lt;/h2&gt;

&lt;p&gt;For doing any multimedia, &lt;a href="https://leogdion.name/2019/06/13/podcasting-getting-started-content-recording-audience/"&gt;including podcasting&lt;/a&gt;, I recommend two suites: Adobe or Apple. First, &lt;a href="https://www.adobe.com/?ref=empowerapps"&gt;Adobe’s Creative Cloud&lt;/a&gt; is great if that is a focus of what you do. For instance, I’ve used Photoshop, Illustrator, Premier, and Audition and each have helped with artwork, video production, and podcast production. However if its steep price is too much for you, I’d recommend looking at what Apple provides for free with iMovie and GarageBand. Most importantly, both offer plenty for beginners as well as intermediates before you move to Apple’s Logic or Final Cut Pro.&lt;/p&gt;

&lt;p&gt;Similarly, for recording video I use &lt;a href="https://obsproject.com"&gt;OBS&lt;/a&gt; as well as &lt;a href="https://www.filmicpro.com/?ref=empowerapps"&gt;FiLMiC Pro&lt;/a&gt;. OBS is great for live streaming demos or tutorials as well as on-screen recording. Conversely, OBS has a learning curve but there’s a lot you can do as a beginner. On the other hand for recording my presentations or video of myself, I use FiLMiC Pro on my iPhone. For one thing as advanced as iPhones are, you can do videos at 4K resolution and 60 Frames Per Second. In addition, I also use &lt;a href="https://itunes.apple.com/us/app/filmic-remote/id661488661?ref=empowerapps"&gt;FiLMiC Remote&lt;/a&gt; on a second iPhone to preview and control the recording as it is being done.&lt;/p&gt;

&lt;p&gt;Afterwards once I’ve edited the video or audio recording, I’ll need to share it with my audience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c-_GpHW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/sara-kurfess-6lcT2kRPvnI-unsplash-e1564280259581-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c-_GpHW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/sara-kurfess-6lcT2kRPvnI-unsplash-e1564280259581-1024x512.jpg" alt="Social Media Apps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Marketing Apps
&lt;/h2&gt;

&lt;p&gt;Social media can be quite overwhelming, which is why I have a set of productivity apps to keep me active as opposed to distracted. For instance, &lt;a href="https://buffer.com/?ref=empowerapps"&gt;Buffer&lt;/a&gt; is a great way to make sure your social media queue is active without constantly being reminded by what’s out there. Furthermore, Buffer can connect with several social media accounts as well as allow you to schedule posts with existing media. Besides social media, email is still actively used by many folks. Therefore, &lt;a href="https://mailchimp.com"&gt;Mailchimp&lt;/a&gt; is a great service for starting your own email list. For instance, whenever I need to update folks on products, services, content; Mailchimp allows for me to automate and schedule email out to my various audiences.&lt;/p&gt;

&lt;p&gt;Along with email, there are other ways to contact my business partners and clients.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9RCHfMgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/room-B_8FwpJICIo-unsplash-e1564280315200-1024x512.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9RCHfMgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leogdion.name/wp-content/uploads/2019/07/room-B_8FwpJICIo-unsplash-e1564280315200-1024x512.jpg" alt="Chatting and Meeting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication Apps
&lt;/h2&gt;

&lt;p&gt;Besides email I use &lt;a href="https://slack.com/?ref=empowerapps"&gt;Slack&lt;/a&gt; pretty frequently. Slack is a great way to communicate with a team, find a community, or share documents. Notably, there is practically a Slack community for all sorts of developer languages, frameworks, and tools. In addition, Slack also uses Markdown for text formatting, has great shortcuts to channels and folks, and a decent bot and developer ecosystem for customization.&lt;/p&gt;

&lt;p&gt;When a Slack message or email won’t do, I typically setup video meetings with &lt;a href="https://zoom.us/"&gt;Zoom&lt;/a&gt;. Most importantly, what Zoom brings to video conferencing is simplicity and the ability to just work. Besides its app (which is offered on multiple platforms), Zoom requires nothing else. After finding the right time for the meeting, I’ll schedule a time and send a link to the meeting using Zoom. Zoom also allows for recording of video calls for later reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Over Optimizing Productivity Apps
&lt;/h2&gt;

&lt;p&gt;Finding the best productivity apps can be great but avoid being sucked in by it’s endless list of features. Have it do the job you want and be done with it. One of the biggest time sucks is over optimization of apps as well. Don’t spend too much time finding the right app or learning every shortcut and feature it offers.&lt;/p&gt;

&lt;p&gt;I hope this list of productivity apps is helpful to you or wherever you work. If you are interested in learning more check out my podcast episodes with Erik Gillespie &lt;a href="http://okproductive.com"&gt;OK Productive&lt;/a&gt;. Especially episodes &lt;a href="https://share.transistor.fm/s/c118081d"&gt;#7 Top Apps&lt;/a&gt; and &lt;a href="https://share.transistor.fm/s/584c906b"&gt;#16 Productivity Apps&lt;/a&gt;&lt;/p&gt;

</description>
      <category>remotework</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Swift Package Continuous Integration Guide</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Fri, 13 Mar 2020 14:27:53 +0000</pubDate>
      <link>https://dev.to/leogdion/swift-package-continuous-integration-guide-533i</link>
      <guid>https://dev.to/leogdion/swift-package-continuous-integration-guide-533i</guid>
      <description>&lt;p&gt;Swift packages offer an easy manageable way to share code and functionality. If you wish to create your own package, it’s important to make sure your code works where it's supposed to and the quality is good. Most importantly, continuous integration is a great way to ensure that. If you are interested in learning why continuous integration is important, &lt;a href="https://brightdigit.com/blog/2020/03/02/ios-continuous-integration-avoid-merge-hell/" rel="noopener noreferrer"&gt;check out this article on avoiding &lt;em&gt;merge hell&lt;/em&gt;&lt;/a&gt;. Therefore, in this article I am going to show you how to setup Swift package continuous integration.&lt;/p&gt;

&lt;p&gt;Specifically, I am going to break down the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basics of Creating a Package&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Designating Platforms and Operating Systems&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting Up Travis-CI and GitHub Actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adding Linux Support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing and Code Coverage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linting, Formatting, and Code Quality&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automating Code Documentation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributing and Sharing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Samples and Examples&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's important to realize is that Swift packages are reusable pieces of code which encapsulate a set of functionality. In the end, there are two ways to create a Swift package: via &lt;em&gt;Xcode&lt;/em&gt; or command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Under the Xcode menu, go to &lt;code&gt;File &amp;gt; New &amp;gt; Swift Package&lt;/code&gt; and follow the corresponding dialog. Alternatively, you can use the swift command line tool to create your package. First, create an empty directory and run the create package subcommand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;mkdir &lt;/span&gt;New-Package
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; swift package init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the end, you should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;Source&lt;/em&gt; directory for your main source code&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;Tests&lt;/em&gt; directory for your testing code&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;Package.swift&lt;/em&gt; containing the configuration in Swift of your code&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Specifying Platforms and Devices &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Fplatforms-and-devices.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Fplatforms-and-devices.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before distributing your Swift package, it’s important to note which operating systems or platforms your code can run on. In the past I’ve reasonably assumed a Swift package would work on watchOS or Linux for instance. Only after adding the dependency and attempting to compile, did I realize the incompatibility issue. If you use an API that is limited to certain platforms, you have two options.&lt;/p&gt;
&lt;h3&gt;
  
  
  Specify via Package
&lt;/h3&gt;

&lt;p&gt;Firstly, you can specify an operating system and version in the &lt;code&gt;Package.swift&lt;/code&gt; under the &lt;code&gt;platforms&lt;/code&gt; property:&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="o"&gt;...&lt;/span&gt;
    &lt;span class="nv"&gt;platforms&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;macOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v10_15&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v13&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;watchOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tvOS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v13&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Using Attributes and API Availability
&lt;/h3&gt;

&lt;p&gt;On the other hand, you may want to offer some functionality on some devices. With this in mind, you can use the attributes and API availability checks. In other words the &lt;code&gt;available&lt;/code&gt; attribute allows you to mark certain functionality of your Swift package unavailable on certain operating systems and versions.&lt;/p&gt;

&lt;p&gt;In addition, by doing API availability checks you can supply the correct implementation based on operating system and version. Furthermore, whenever you may need to import certain frameworks which may be required but may not be available, you can use &lt;code&gt;canImport&lt;/code&gt;, as well.&lt;/p&gt;

&lt;p&gt;Here's an example of extending &lt;code&gt;CGFloat&lt;/code&gt; for all operating systems, but importing &lt;code&gt;CoreGraphics&lt;/code&gt;, when possible:&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="cp"&gt;#if canImport(CoreGraphics)&lt;/span&gt;
  &lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;CoreGraphics&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;clean&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="nf"&gt;truncatingRemainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dividingBy&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="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&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="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"%.0f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;description&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;Be that as it may, if you are planning on supporting all operating systems which support Swift then there is no need to do this. Regardless, it may be worth spending some time verifying and updating this property accordingly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Continuous Integration? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Having properly setup your package and provided correct compatibility, it’s important to make sure your package works. Additionally, you may want to make sure each change to your code works correctly. Luckily, this is where Continuous Integration comes in.&lt;/p&gt;

&lt;p&gt;Continuous integration (CI) is the software practice where small code changes are frequently tested with the rest of the code to ensure nothing breaks as it changes. In other words, with CI we can make sure each change works correctly by integrating a service with our code.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/continuous-integration-with-kyle-newsome"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Continuous Integration with Kyle Newsome&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show
      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-continuous-integration-with-kyle-newsome" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-continuous-integration-with-kyle-newsome" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-continuous-integration-with-kyle-newsome" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-continuous-integration-with-kyle-newsome" alt="EmpowerApps.Show" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F79%2Fbc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;

  &lt;div class="hidden-audio" id="hidden-audio-continuous-integration-with-kyle-newsome"&gt;
  
    
    Your browser does not support the audio element.
  
  &lt;div id="progressBar" class="audio-player-display"&gt;
    &lt;a href="/empowerappsshow/continuous-integration-with-kyle-newsome"&gt;
      &lt;img id="episode-profile-image" alt="Continuous Integration with Kyle Newsome" width="420" height="420" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F79%2Fbc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
      &lt;img id="animated-bars" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fanimated-bars-4e8c57c8b58285fcf7d123680ad8af034cd5cd43b4d9209fe3aab49d1e9d77b3.gif" alt="animated volume bars"&gt;
    &lt;/a&gt;
    &lt;span id="barPlayPause"&gt;
      &lt;img class="butt play-butt" alt="play" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png"&gt;
      &lt;img class="butt pause-butt" alt="pause" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png"&gt;
    &lt;/span&gt;
    &lt;span id="volume"&gt;
      &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
        &lt;span id="volbutt"&gt;
          &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fvolume-cd20707230ae3fc117b02de53c72af742cf7d666007e16e12f7ac11ebd8130a7.png"&gt;
        &lt;/span&gt;
        &lt;span class="range-wrapper"&gt;
          
        &lt;/span&gt;
      &lt;/span&gt;
      &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
        &lt;img alt="volume-mute" class="icon-img" height="16" width="16" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fvolume-mute-8f08ec668105565af8f8394eb18ab63acb386adbe0703afe3748eca8f2ecbf3b.png"&gt;
      &lt;/span&gt;
      &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
      &lt;span id="buffer"&gt;&lt;/span&gt;
      &lt;span id="progress"&gt;&lt;/span&gt;
      &lt;span id="time"&gt;initializing...&lt;/span&gt;
      &lt;span id="closebutt"&gt;×&lt;/span&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Choosing a service for Swift Package Continuous Integration
&lt;/h3&gt;

&lt;p&gt;What’s important to realize is that by using a cloud service for your Swift package, you can make sure your package works everywhere. Often times, we may be have some source, artifact, or tool required to build our code. However with a cloud service, you can ensure that if your Swift package builds and tests in the cloud it will work for anyone else.&lt;/p&gt;

&lt;p&gt;Luckily, there are some great services out there to help your Swift package especially if it’s a public GitHub repository. At the present time, unfortunately, some services &lt;strong&gt;only&lt;/strong&gt; support Continuous Integration for iOS Applications rather than Swift packages such as &lt;strong&gt;&lt;a href="https://circleci.com" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://www.bitrise.io" rel="noopener noreferrer"&gt;Bitrise&lt;/a&gt;&lt;/strong&gt;. Be that as it may, &lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt; as well as the most recent &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; allow for Swift Package Continuous Integration.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2FTravisCI-Full-Color-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2FTravisCI-Full-Color-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Travis-CI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt; is one of the older Continuous Integration services out there. Most importantly for public repositories, &lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt; is completely free. In other words, you can configure your Swift package on &lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt;. In order to configure your repository, signup with &lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt; by linking your GitHub account or organization. Next you need to setup your &lt;code&gt;.travis.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Notably, there are three key components for setting up a Swift package in Travis-CI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specifying the correct operating system and Xcode version&lt;/li&gt;
&lt;li&gt;Building and testing your code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, here is a simple &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;objective-c&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;osx&lt;/span&gt;
&lt;span class="na"&gt;osx_image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xcode11.3&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;swift build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;swift test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first three properties setup the virtual machine which &lt;strong&gt;&lt;a href="https://travis-ci.com" rel="noopener noreferrer"&gt;Travis-CI&lt;/a&gt;&lt;/strong&gt; uses. Next, the lines under &lt;code&gt;script&lt;/code&gt; specify the commands Travis-CI needs to run to verify the Swift package is working. In this case, &lt;strong&gt;since we are not building from an Xcode project or workspace, we need to specify our own &lt;em&gt;custom&lt;/em&gt; commands.&lt;/strong&gt; In other words, rather than using &lt;em&gt;xcodebuild&lt;/em&gt;, the Swift command line tool will build and test our package.&lt;/p&gt;

&lt;p&gt;While Travis-CI is the most experienced cloud CI service out there, recently GitHub has also offered its own service with &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2F44036562-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2F44036562-2.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Github Actions
&lt;/h3&gt;

&lt;p&gt;With the fairly recent release of &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt;, you can setup Swift package continuous integration right from your repo. Most importantly &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; is completely free for public repositories. Therefore, let’s breakdown the functionality of &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  GitHub Actions Components - Workflows, Actions, Jobs and more
&lt;/h4&gt;

&lt;p&gt;In order to setup our Swift package continuous integration in GitHub Actions, we need to understand the components. Similar to Travis-CI, GitHub uses YAML for its configuration. Specifically these YAML files are known as workflow files. For example, here is a sample with the name &lt;code&gt;macOS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macOS&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In contrast to Travis-CI, you can setup multiple of these files. Therefore as long as you store them in your repository under the &lt;code&gt;.github/workflow&lt;/code&gt; folder, &lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; will execute each of these workflow files on trigger.&lt;/p&gt;

&lt;p&gt;Speaking of &lt;em&gt;trigger&lt;/em&gt;, you can specify many triggers. However in the case of our Swift package, we will only be using the &lt;code&gt;push&lt;/code&gt; trigger to activate this workflow.&lt;/p&gt;

&lt;p&gt;Below the &lt;code&gt;on&lt;/code&gt; trigger, we have setup one job under &lt;code&gt;jobs&lt;/code&gt; called &lt;code&gt;build&lt;/code&gt;. With in the &lt;code&gt;build&lt;/code&gt; job, we have specified the runner type (i.e virtual environment) of &lt;code&gt;macOS-latest&lt;/code&gt;. In other words, it will be using the latest version of macOS to run the series of steps.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  GitHub Actions - Step By Step
&lt;/h5&gt;

&lt;p&gt;Below the runner type property are the series of steps specified. In this case, the first step with the single &lt;code&gt;uses&lt;/code&gt; property checks out the code from the repository. While the following steps have a &lt;code&gt;name&lt;/code&gt; label and a &lt;code&gt;run&lt;/code&gt; command to execute: first building the Swift package (&lt;code&gt;swift build&lt;/code&gt;) then running tests provided (&lt;code&gt;swift test&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;What’s important to note is that each needs a custom command (via &lt;code&gt;run&lt;/code&gt;) with a &lt;code&gt;name&lt;/code&gt; or to use a prebuilt action from the GitHub repo such as &lt;code&gt;actions/checkout@v2&lt;/code&gt; to pull the source code from the repository. Unfortunately many of the GitHub Actions provided on GitHub may not be compatible with macOS due to various requirements.&lt;/p&gt;

&lt;p&gt;Luckily you should have Continuous Integration setup for your Swift package in both Travis-CI and GitHub Actions. However if you wish to support Linux with your Swift package, it is import to configure the Swift package continuous integration for a Linux environment as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2Fubuntu_black-orange_hex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2Fubuntu_black-orange_hex.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Linux Support for Swift Package Continuous Integration &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you wish for your Swift package to be supported everywhere, it might be a good idea to support Linux. Therefore, it’s important to have your Swift package Continuous integration to extend to Linux. Thankfully both Travis-CI and GitHub Action support Linux (i.e. Ubuntu) as well as the configuration of more than one environment per repository. First, let’s understand how build matrices work in Travis-CI.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuring Travis-CI for Linux
&lt;/h4&gt;

&lt;p&gt;With Travis-CI, we can use a build matrix to include more than one environment. In other words, Travis-CI will run each environment in the build matrix in parallel. Therefore, let’s swap the top section specifying only macOS from above with a build matrix including both macOS and Linux (i.e. Ubuntu 18.04-bionic):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
      &lt;span class="na"&gt;dist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bionic&lt;/span&gt;
      &lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;osx&lt;/span&gt;
      &lt;span class="na"&gt;osx_image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xcode11.3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, it will run each phase in parallel on Ubuntu as well as macOS. However we'll need to make changes to both of the these sections in order to support Linux. Most importantly, we will need to install Swift.&lt;/p&gt;

&lt;p&gt;Therefore, we will move or create the &lt;code&gt;script&lt;/code&gt; and &lt;code&gt;before_install&lt;/code&gt; phases into separate bash scripts and update &lt;code&gt;.travis.yml&lt;/code&gt; accordingly:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
      &lt;span class="na"&gt;dist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bionic&lt;/span&gt;
      &lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;osx&lt;/span&gt;
      &lt;span class="na"&gt;osx_image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xcode11.3&lt;/span&gt;
&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Scripts/before_install.sh&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Scripts/script.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next let’s create a script for &lt;code&gt;before_install&lt;/code&gt; named &lt;code&gt;before_install.sh&lt;/code&gt; under the &lt;code&gt;Scripts&lt;/code&gt; folder with the following code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'osx'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# install macOS prerequistes&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'linux'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# download swift&lt;/span&gt;
  wget https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
  &lt;span class="c"&gt;# extract the archive&lt;/span&gt;
  &lt;span class="nb"&gt;tar &lt;/span&gt;xzf swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
  &lt;span class="c"&gt;# include the swift command in the PATH&lt;/span&gt;
  &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/swift-5.1.3-RELEASE-ubuntu18.04/usr/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Within the bash script, we check the environment variable &lt;code&gt;TRAVIS_OS_NAME&lt;/code&gt; setup by Travis-CI. With the variable, we check whether it is &lt;code&gt;osx&lt;/code&gt; for a macOS environment or &lt;code&gt;linux&lt;/code&gt; for the Ubuntu environment.&lt;/p&gt;

&lt;p&gt;Since Xcode is not available on Ubuntu, we need to manually within the bash script, download and extract Swift. Lastly we need to include the directory path of the Swift command tool within the environment &lt;code&gt;PATH&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Correspondingly we need to make sure the &lt;code&gt;PATH&lt;/code&gt; is updated in the &lt;code&gt;Scripts/script.sh&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'osx'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# What to do in macOS&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'linux'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# What to do in Ubunutu&lt;/span&gt;
  &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/swift-5.1.3-RELEASE-ubuntu18.04/usr/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;swift build
swift &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Therefore the only major change within the &lt;code&gt;script&lt;/code&gt; section of the Travis-CI configuration is including the path to the Swift command line tool.&lt;/p&gt;

&lt;p&gt;As a result, each time a push is made to the repository, Travis-CI will run both a macOS and Ubuntu process. In effect, we have setup Swift package continuous integration for both operating systems in Travis-CI. Accordingly, let’s do the same thing for GitHub Actions.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuring GitHub Actions for Linux
&lt;/h4&gt;

&lt;p&gt;While Travis-CI requires us to check the operating system within the build script, GitHub Actions allows us to use separate workflow files for each operating system.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-18.04&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download Swift 5.1.3&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wget https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract Swift 5.1.3&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tar xzf swift-5.1.3-RELEASE-ubuntu18.04.tar.gz&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add Path&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "::add-path::$GITHUB_WORKSPACE/swift-5.1.3-RELEASE-ubuntu18.04/usr/bin"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this case, each command is stored within an individual step. As can be seen, the one custom part is the method we use to add the path using GitHub Actions logging commands and variables. With &lt;code&gt;echo "::add-path::$GITHUB_WORKSPACE/swift-5.1.3-RELEASE-ubuntu18.04/usr/bin"&lt;/code&gt;, we update the &lt;code&gt;PATH&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;As a result, your Swift package continuous integration should support Linux via Travis-CI and GitHub Action. However, there are a few steps in order to support Linux when it comes to testing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing, CI, and Linux &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Flinux-test-swift.png%3Ffit%3D640%252C316%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Flinux-test-swift.png%3Ffit%3D640%252C316%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to verifying whether your package works correctly, having the right unit tests are a major component of that. Luckily, if you are using the XCTest framework and setup the CI scaffold previously described, you should be good to go. However with Linux, XCTest will not automatically provide all the correct tests in your application without some modifications. There are a few ways of doing this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manually update your XCTestManifests.swift and LinuxMain.swift :(&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;swift test --generate-linuxmain&lt;/code&gt; &lt;strong&gt;before commit on your macOS machine&lt;/strong&gt; to let the swift command line tool update your LinuxMain.swift.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update your CI for Linux&lt;/strong&gt; to run &lt;code&gt;swift test --enable-test-discovery&lt;/code&gt; which will automatically discover and run your tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are interested in learning more about this check out Ole Begemann’s piece on &lt;a href="https://oleb.net/blog/2017/03/keeping-xctest-in-sync/" rel="noopener noreferrer"&gt;keeping XCTest in sync&lt;/a&gt; as well as &lt;a href="https://oleb.net/2020/swift-test-discovery/" rel="noopener noreferrer"&gt;how automatic test discovery works&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have our unit tests working correctly, let's look into keeping tracking of code coverage.&lt;/p&gt;
&lt;h3&gt;
  
  
  Integrating Code Coverage
&lt;/h3&gt;

&lt;p&gt;Code coverage is a good way to keep track of how well your unit tests are handling. Luckily there are some great services out there to keep track of your code coverage as you build your Swift package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiq2saofvo35ubq3mub3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiq2saofvo35ubq3mub3p.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  CodeCov
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://codecov.io/" rel="noopener noreferrer"&gt;CodeCov.io&lt;/a&gt;&lt;/strong&gt; is one such service which we can plugin into our Swift Package Continuous Integration setup. However, once you have signed up and added your public repository, it will take some configuration to make it work completely.&lt;/p&gt;

&lt;p&gt;For instance, we must make sure that the tests, build a report, convert the report to a compatible format, then lastly upload the the report to &lt;strong&gt;&lt;a href="http://codecov.io/" rel="noopener noreferrer"&gt;CodeCov.io&lt;/a&gt;&lt;/strong&gt;. Building the report when you run the unit tests is fairly easy. In this case, we simply need to add the flag &lt;code&gt;--enable-code-coverage&lt;/code&gt; to our &lt;code&gt;swift test&lt;/code&gt; for both Travis-CI and GitHub Actions; macOS and Linux:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swift &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--enable-code-coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we need to prepare the report for upload using &lt;code&gt;llvm-cov&lt;/code&gt;. With this in mind, on macOS you can use &lt;code&gt;xcrun&lt;/code&gt; to run &lt;code&gt;llvm-cov&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcrun llvm-cov &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"lcov"&lt;/span&gt; .build/debug/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{FRAMEWORK_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;PackageTests.xctest/Contents/MacOS/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{FRAMEWORK_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;PackageTests &lt;span class="nt"&gt;-instr-profile&lt;/span&gt; .build/debug/codecov/default.profdata &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; info.lcov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Corresponding in Linux, we can run &lt;code&gt;llvm-cov&lt;/code&gt; manually:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llvm-cov &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"lcov"&lt;/span&gt; .build/x86_64-unknown-linux/debug/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{FRAMEWORK_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;PackageTests.xctest &lt;span class="nt"&gt;-instr-profile&lt;/span&gt; .build/debug/codecov/default.profdata &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; info.lcov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Simply replace &lt;code&gt;${{FRAMEWORK_NAME}}&lt;/code&gt; with your Swift package name or even better setup an environment variable in Travis-CI and GitHub Actions.&lt;/p&gt;

&lt;p&gt;Lastly, we need to upload the report using the Bash script provided by CodeCov.io:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl https://codecov.io/bash&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;While Travis-CI automatically integrates with CodeCov.io, GitHub does require &lt;a href="https://docs.codecov.io/docs/about-the-codecov-bash-uploader" rel="noopener noreferrer"&gt;manually setting up the token for CodeCov.io&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, go to your project in CodeCov.io and copy the token from the project overview.&lt;/li&gt;
&lt;li&gt;Go to your GitHub repository settings and under &lt;em&gt;Secrets&lt;/em&gt; add the token under the name &lt;code&gt;CODECOV_TOKEN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Under both the macOS and ubuntu workflow files, add the &lt;code&gt;CODECOV_TOKEN&lt;/code&gt; as the environment variable under the upload step.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, here’s the Ubuntu workflow file which uses an environment variable for the Swift package name and maps the &lt;code&gt;CODECOV_TOKEN&lt;/code&gt; secret to the uploader command environment variable:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;    
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift test --enable-code-coverage&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare Code Coverage&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llvm-cov export -format="lcov" .build/x86_64-unknown-linux/debug/${{ env.PACKAGE_NAME }}PackageTests.xctest -instr-profile .build/debug/codecov/default.profdata &amp;gt; info.lcov&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload to CodeCov.io&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash &amp;lt;(curl https://codecov.io/bash)&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;CODECOV_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CODECOV_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that we have completed setting up a code coverage report with &lt;strong&gt;CodeCov.io&lt;/strong&gt;, Let’s talk about ensuring good code quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2Fmedal-150x150.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F02%2Fmedal-150x150.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Quality and CI &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There are some great automated ways we can keep up code quality inside our Swift package continuous integration. However, nothing replaces a good code review. If you can, have some sort of code review process by someone else. If it’s difficult to find someone else, I suggest reviewing a Swift package’s code after some down time to ensure you can have a fresh look at your code.&lt;/p&gt;

&lt;p&gt;Regardless, let’s look at some of the ways we can automate code quality checks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Formatting, Beautification, and Linting
&lt;/h3&gt;

&lt;p&gt;There are two command line tools I use to maintain quality code while keeping formatting consistent: &lt;strong&gt;&lt;a href="https://github.com/nicklockwood/SwiftFormat" rel="noopener noreferrer"&gt;SwiftFormat&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/realm/SwiftLint" rel="noopener noreferrer"&gt;SwiftLint&lt;/a&gt;&lt;/strong&gt;. Fortunately, each application can be installed via Homebrew. Therefore, we can use Homebrew bundle to automate the installation of both applications inside our Swift package continuous integration. With this in mind, add a file called &lt;code&gt;Brewfile&lt;/code&gt; to the root of repository with the following text:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew "swiftformat"
brew "swiftlint"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next we need to add the installation these applications in the earliest part of our CI setup. However these applications will only work on macOS and we need to verify that as well. Therefore we modify our &lt;code&gt;before_install.sh&lt;/code&gt; script for Travis-CI with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'osx'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;brew update
  brew bundle
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'linux'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Meanwhile, for Github Actions, we simply need to add steps to our macOS workflow file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prepare Build&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;brew bundle&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly we need to add the following command to verify code quality after the installation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swiftformat &lt;span class="nt"&gt;--lint&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; swiftlint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In short, this command will run both applications in the CI process. Specifically we run &lt;code&gt;swiftformat&lt;/code&gt; in linter mode, since our expectation is that the developer has already formatted the code correctly before commit. Correspondingly, with &lt;code&gt;swiftlint&lt;/code&gt;, you can use the &lt;code&gt;autocorrect&lt;/code&gt; subcommand to fix some linter errors in your code before commit.&lt;/p&gt;

&lt;p&gt;Again, for Travis-CI, verify the &lt;code&gt;$TRAVIS_OS_NAME&lt;/code&gt; is &lt;code&gt;osx&lt;/code&gt;, so the CI doesn’t run the tool in Linux.&lt;/p&gt;

&lt;p&gt;Beside installation and execution of the tools within the Swift package continuous integration, you should probably add configuration files for both tools. In brief, these are &lt;code&gt;.swiftformat&lt;/code&gt; and &lt;code&gt;.swiftlint.yml&lt;/code&gt;. Futhermore, check out both the &lt;strong&gt;&lt;a href="https://github.com/nicklockwood/SwiftFormat" rel="noopener noreferrer"&gt;SwiftFormat&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/realm/SwiftLint" rel="noopener noreferrer"&gt;SwiftLint&lt;/a&gt;&lt;/strong&gt; projects for details on how setup these configurations.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/managing-code-quality-with-anne-cahalan"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Managing Code Quality with Anne Cahalan&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show
      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-managing-code-quality-with-anne-cahalan" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-managing-code-quality-with-anne-cahalan" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-managing-code-quality-with-anne-cahalan" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-managing-code-quality-with-anne-cahalan" alt="EmpowerApps.Show" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F79%2Fbc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;

  &lt;div class="hidden-audio" id="hidden-audio-managing-code-quality-with-anne-cahalan"&gt;
  
    
    Your browser does not support the audio element.
  
  &lt;div id="progressBar" class="audio-player-display"&gt;
    &lt;a href="/empowerappsshow/managing-code-quality-with-anne-cahalan"&gt;
      &lt;img id="episode-profile-image" alt="Managing Code Quality with Anne Cahalan" width="420" height="420" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F79%2Fbc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
      &lt;img id="animated-bars" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fanimated-bars-4e8c57c8b58285fcf7d123680ad8af034cd5cd43b4d9209fe3aab49d1e9d77b3.gif" alt="animated volume bars"&gt;
    &lt;/a&gt;
    &lt;span id="barPlayPause"&gt;
      &lt;img class="butt play-butt" alt="play" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png"&gt;
      &lt;img class="butt pause-butt" alt="pause" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png"&gt;
    &lt;/span&gt;
    &lt;span id="volume"&gt;
      &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
        &lt;span id="volbutt"&gt;
          &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fvolume-cd20707230ae3fc117b02de53c72af742cf7d666007e16e12f7ac11ebd8130a7.png"&gt;
        &lt;/span&gt;
        &lt;span class="range-wrapper"&gt;
          
        &lt;/span&gt;
      &lt;/span&gt;
      &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
        &lt;img alt="volume-mute" class="icon-img" height="16" width="16" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fvolume-mute-8f08ec668105565af8f8394eb18ab63acb386adbe0703afe3748eca8f2ecbf3b.png"&gt;
      &lt;/span&gt;
      &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
      &lt;span id="buffer"&gt;&lt;/span&gt;
      &lt;span id="progress"&gt;&lt;/span&gt;
      &lt;span id="time"&gt;initializing...&lt;/span&gt;
      &lt;span id="closebutt"&gt;×&lt;/span&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Cloud-Based Code Quality Services
&lt;/h3&gt;

&lt;p&gt;Besides &lt;strong&gt;&lt;a href="https://github.com/nicklockwood/SwiftFormat" rel="noopener noreferrer"&gt;SwiftFormat&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/realm/SwiftLint" rel="noopener noreferrer"&gt;SwiftLint&lt;/a&gt;&lt;/strong&gt;, there are a few cloud based code quality tools which easily integrate with your public GitHub repository. Therefore, you may be interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.codefactor.io/" rel="noopener noreferrer"&gt;CodeFactor.io&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://codebeat.co" rel="noopener noreferrer"&gt;CodeBeat&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://codeclimate.com" rel="noopener noreferrer"&gt;CodeClimate&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://houndci.com" rel="noopener noreferrer"&gt;HoundCI&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After having setup these various tools, it’s worth taking a look at some various issues which may crop up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Code Quality Issues
&lt;/h3&gt;

&lt;p&gt;Now that we have setup our Swift package continuous integration and plugged in several services, there are few issues you could resolve which will show up:&lt;/p&gt;

&lt;h4&gt;
  
  
  Cyclomatic Complexity
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Cyclomatic Complexity&lt;/em&gt; refers to the complexity of the code specifically when it comes to testability. In the end, if your code contains several logical paths, it is best to break these up. For instance, using &lt;em&gt;Protocol Oriented Programming&lt;/em&gt;, you can have a protocol to test the case. Then, for each case use individual implementations and store them in an array. For instance, rather than:&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&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;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&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="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Use a protocol which does:&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;protocol&lt;/span&gt; &lt;span class="kt"&gt;Doer&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;test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;a&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="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;b&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;Result&lt;/span&gt;&lt;span class="p"&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;implementations&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Doer&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="kt"&gt;FooDoer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="kt"&gt;BarDoer&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Result&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;implementation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;implmentations&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;As a result, testing and maintaining this code becomes much more simple.&lt;/p&gt;
&lt;h4&gt;
  
  
  Cognitive Complexity
&lt;/h4&gt;

&lt;p&gt;While Cyclomatic Complexity determines how difficult your code will be to test, Cognitive Complexity is how difficult it is to read and understand. Therefore much of this involves breaks in logic, and unnecessary loop statements. However by making your code flow clearly from top to bottom this can be avoided.&lt;/p&gt;
&lt;h4&gt;
  
  
  File and Function Too Long
&lt;/h4&gt;

&lt;p&gt;One of the easiest metrics of complexity is the length of your files and functions. In the end, simply refactoring should resolve the issue. To put it differently, break down large functions, classes, and structs into smaller components. At the same time, you may find a class which is difficult to split up such as a &lt;code&gt;UITableViewController&lt;/code&gt;. In this case, Swift extensions are a great way to resolve this.&lt;/p&gt;
&lt;h4&gt;
  
  
  Assignment Branch Condition
&lt;/h4&gt;

&lt;p&gt;Assignment Branch Condition typically is calculated based on the number of assignments, branches, and conditions as opposed to simply length. Therefore, this can be resolved by separating your functions into smaller pieces. In other words, reduce these complex elements from one function into several.&lt;/p&gt;



&lt;p&gt;Many of these code quality issues should be resolved, however it is good to not be overly concerned with some of these metrics. Similar to code coverage, it is much more a case-by-case need for resolution.&lt;/p&gt;

&lt;p&gt;Additionally there can easily be instances of false positives such as &lt;em&gt;identical code&lt;/em&gt; issues. In the end, it’s important to have a measured but determined approach to code quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Fbook-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flearningswift.brightdigit.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2020%2F03%2Fbook-2.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Documenting Your Swift Package &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you intend to distribute your Swift package to the public then it’s important to document your code and make that documentation easily available. In the first place, take a look at &lt;a href="https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/" rel="noopener noreferrer"&gt;Apple’s guidance on documenting Swift code&lt;/a&gt; as well as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sarunw.com/posts/swift-documentation/" rel="noopener noreferrer"&gt;&lt;strong&gt;Swift Documentation&lt;/strong&gt; by Sarun Wongpatcharapakorn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nshipster.com/swift-documentation/" rel="noopener noreferrer"&gt;&lt;strong&gt;Swift Documentation&lt;/strong&gt; - NSHipster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve properly documented your Swift package API, let’s add code documentation to our Swift package continuous integration.&lt;/p&gt;

&lt;p&gt;Primarily, you have the option of using either &lt;strong&gt;&lt;a href="https://github.com/realm/jazzy" rel="noopener noreferrer"&gt;Jazzy by Realm&lt;/a&gt;&lt;/strong&gt; or &lt;a href="https://github.com/eneko/SourceDocs" rel="noopener noreferrer"&gt;&lt;strong&gt;SourceDocs&lt;/strong&gt;&lt;/a&gt;. Each has their advantage depending on whether you wish to build a complete static HTML site. In that case, I would recommend &lt;strong&gt;&lt;a href="https://github.com/realm/jazzy" rel="noopener noreferrer"&gt;Jazzy&lt;/a&gt;&lt;/strong&gt;. Especially considering the maturity of &lt;strong&gt;&lt;a href="https://github.com/realm/jazzy" rel="noopener noreferrer"&gt;Jazzy&lt;/a&gt;&lt;/strong&gt;, it can be an excellent tool. On the other hand, if you wish to simply output Markdown for your package documentation, I’d recommend &lt;a href="https://github.com/eneko/SourceDocs" rel="noopener noreferrer"&gt;&lt;strong&gt;SourceDocs&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using SourceDocs
&lt;/h3&gt;

&lt;p&gt;To build documentation using &lt;code&gt;sourcedocs&lt;/code&gt;, first build your Swift package using &lt;code&gt;swift build&lt;/code&gt;. Once your package is built, you run &lt;code&gt;sourcedocs&lt;/code&gt; using:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sourcedocs generate &lt;span class="nt"&gt;--spm-module&lt;/span&gt; PACKAGE_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Additionally, you can use a different output directory besides &lt;code&gt;Documentation&lt;/code&gt;, such as &lt;code&gt;docs&lt;/code&gt;. In order to do that, you can use the flag &lt;code&gt;--output-folder&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sourcedocs generate &lt;span class="nt"&gt;--spm-module&lt;/span&gt; PACKAGE_NAME &lt;span class="nt"&gt;--output-folder&lt;/span&gt; docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Furthermore, we can take the next step and integrate &lt;code&gt;sourcedocs&lt;/code&gt; into our Swift package Continuous Integration.&lt;/p&gt;
&lt;h4&gt;
  
  
  Adding SourceDocs to Swift Package Continuous Integration
&lt;/h4&gt;

&lt;p&gt;Similar to our other tools, we need to add &lt;code&gt;sourcedocs&lt;/code&gt; to our Homebrew bundle file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew "swiftformat"
brew "swiftlint"
brew "sourcedocs"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next in our macOS GitHub Action workflow file, we can add a step to build the documentation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Documentation&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sourcedocs generate --spm-module ${{ env.PACKAGE_NAME }} --output-folder docs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly, in order to make sure our change is pushed, we need to add a step to commit and push any documentation changes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit files&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git config --local user.email "action@github.com"&lt;/span&gt;
        &lt;span class="s"&gt;git config --local user.name "GitHub Action"&lt;/span&gt;
        &lt;span class="s"&gt;git status&lt;/span&gt;
        &lt;span class="s"&gt;git add [DOCUMENTATION DIRECTORY]&lt;/span&gt;
        &lt;span class="s"&gt;git diff-index --quiet HEAD || git commit -m "[github action] Update Docs"&lt;/span&gt;
        &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A point often overlooked, is that this will fail if there is an already existing push committed while this CI takes place. Therefore, in those cases, the CI will fail. If you are concerned, I would recommend looking at using a pull request rather than a direct push to the branch.&lt;/p&gt;

&lt;p&gt;After having built documentation for our swift package, it is important to make our package discoverable to others.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making Your Swift Package Available &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI based on the supported platforms such as Linux&lt;/li&gt;
&lt;li&gt;linting and code quality checks&lt;/li&gt;
&lt;li&gt;code documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;… let’s discuss how we can properly distribute the package to others.&lt;/p&gt;
&lt;h3&gt;
  
  
  SwiftPM
&lt;/h3&gt;

&lt;p&gt;While Swift packages can easily be added simply as a few lines in a &lt;code&gt;Package.swift&lt;/code&gt;, discoverability can be difficult. Luckily thanks to the work of Dave Verwer, the community has a great site with &lt;strong&gt;&lt;a href="http://swiftpm.co" rel="noopener noreferrer"&gt;swiftpm.co&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However there are some checks we should add to make sure your Swift package is valid. Additionally we can add these checks to the Swift package continuous integration.&lt;/p&gt;
&lt;h4&gt;
  
  
  Using &lt;code&gt;jq&lt;/code&gt; to Verify Products
&lt;/h4&gt;

&lt;p&gt;With this intention, we need to make sure that our swift package has at least one valid product. For instance, under the product section of my &lt;code&gt;Package.swift&lt;/code&gt; for my package &lt;strong&gt;&lt;a href="https://github.com/brightdigit/AssetLib" rel="noopener noreferrer"&gt;AssetLib&lt;/a&gt;&lt;/strong&gt;, it has a library product listed:&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="o"&gt;...&lt;/span&gt;
  &lt;span class="nv"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Products define the executables and libraries produced by a package, and make them visible to other packages.&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"AssetLib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"AssetLib"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Fortunately, we can automate this by dumping the JSON of the package and verifying the products listed using &lt;strong&gt;&lt;a href="https://stedolan.github.io/jq/" rel="noopener noreferrer"&gt;jq&lt;/a&gt;&lt;/strong&gt;. &lt;strong&gt;&lt;a href="https://stedolan.github.io/jq/" rel="noopener noreferrer"&gt;jq&lt;/a&gt;&lt;/strong&gt; is a fantastic command-line tool for processing JSON data similar to &lt;em&gt;sed&lt;/em&gt;. Therefore by piping the JSON from the swift subcommand &lt;code&gt;package dump-package&lt;/code&gt; to &lt;code&gt;jq&lt;/code&gt;, we can check the number products:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swift package dump-package | jq &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".products | length &amp;gt; 0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As can be seen, we are using the filter string to check the &lt;code&gt;length&lt;/code&gt; property of the property &lt;code&gt;products&lt;/code&gt; to see if there is more than one product.&lt;/p&gt;

&lt;p&gt;Lastly, we can submit our Swift package for review by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forking &lt;strong&gt;&lt;a href="https://github.com/daveverwer/SwiftPMLibrary" rel="noopener noreferrer"&gt;the Repo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Adding our repos to &lt;code&gt;packages.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Making sure &lt;code&gt;packages.json&lt;/code&gt; is sorted via &lt;code&gt;jq&lt;/code&gt; by running:
&lt;code&gt;echo "$(jq 'sort_by(ascii_downcase)' packages.json)" &amp;gt; packages.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;validate.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a pull request in GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then wait for acceptance to see your package listed at &lt;strong&gt;&lt;a href="http://swiftpm.co" rel="noopener noreferrer"&gt;swiftpm.co&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cocoapods Compatibility
&lt;/h3&gt;

&lt;p&gt;While Swift packages are the future of dependency management, there are several reasons why &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; is still in use. For this reason, it’s a good idea to add support for &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; to your library. Luckily, there are only a few simple steps to add for making our Swift package is compatible.&lt;/p&gt;

&lt;p&gt;Once you have &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; installed, create the &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; spec by running:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pod spec create &lt;span class="si"&gt;$(&lt;/span&gt;git remote get-url origin&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At the present time, you should have a &lt;code&gt;.podspec&lt;/code&gt; file named after your library. Inside the &lt;code&gt;.podspec.&lt;/code&gt; file, add or set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long description under &lt;code&gt;spec.description&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Short summary under &lt;code&gt;spec.summary&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://help.github.com/en/github/building-a-strong-community/adding-a-license-to-a-repository" rel="noopener noreferrer"&gt;Create License File&lt;/a&gt; and set the set license type and file name under &lt;code&gt;spec.license&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your name and email address under &lt;code&gt;spec.author&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.cocoapods.org/syntax/podspec.html#deployment_target" rel="noopener noreferrer"&gt;The deployment targets for each operating system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;spec.source&lt;/code&gt; to the repository url and git tag of the target version&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.source_files&lt;/code&gt; to &lt;code&gt;Sources/**/*.swift&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;spec.swift_versions&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly we can verify our package is valid in our existing continuous integration by including &lt;code&gt;pod lib lint&lt;/code&gt; within the macOS sections of our script.&lt;/p&gt;
&lt;h4&gt;
  
  
  Setting Up An Example Project
&lt;/h4&gt;

&lt;p&gt;Additionally I would encourage creating an example project using your library with targets in each operating system. Moreover, we can also verify our example project builds. After creating the example project in a directory called Example, create a Podfile using &lt;code&gt;pod init&lt;/code&gt;. Then update the &lt;code&gt;Podfile&lt;/code&gt; by adding a reference to your pod in the parent directory:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="s1"&gt;'iOS Example'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Comment the next line if you don't want to use dynamic frameworks&lt;/span&gt;
  &lt;span class="n"&gt;use_frameworks!&lt;/span&gt;
  &lt;span class="n"&gt;pod&lt;/span&gt; &lt;span class="s1"&gt;'PackageName'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'../'&lt;/span&gt;

  &lt;span class="c1"&gt;# Pods for iOS Example&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next to verify the build in our macOS continuous integration, include the following lines:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_OS_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'osx'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
...
  swift package generate-xcodeproj
  pod &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--project-directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Example
  xcodebuild &lt;span class="nt"&gt;-quiet&lt;/span&gt; &lt;span class="nt"&gt;-workspace&lt;/span&gt; Example/Example.xcworkspace &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"iOS Example"&lt;/span&gt;  &lt;span class="nv"&gt;ONLY_ACTIVE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO  &lt;span class="nv"&gt;CODE_SIGN_IDENTITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="nv"&gt;CODE_SIGNING_REQUIRED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO  &lt;span class="nv"&gt;CODE_SIGNING_ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
  xcodebuild &lt;span class="nt"&gt;-quiet&lt;/span&gt; &lt;span class="nt"&gt;-workspace&lt;/span&gt; Example/Example.xcworkspace &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"tvOS Example"&lt;/span&gt;  &lt;span class="nv"&gt;ONLY_ACTIVE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO   &lt;span class="nv"&gt;CODE_SIGN_IDENTITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="nv"&gt;CODE_SIGNING_REQUIRED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO  &lt;span class="nv"&gt;CODE_SIGNING_ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
  xcodebuild &lt;span class="nt"&gt;-quiet&lt;/span&gt; &lt;span class="nt"&gt;-workspace&lt;/span&gt; Example/Example.xcworkspace &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"macOS Example"&lt;/span&gt;  &lt;span class="nv"&gt;ONLY_ACTIVE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO &lt;span class="nv"&gt;CODE_SIGN_IDENTITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="nv"&gt;CODE_SIGNING_REQUIRED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO  &lt;span class="nv"&gt;CODE_SIGNING_ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In other words, this script example for Travis-CI, will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate the Xcode project &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; needs.&lt;/li&gt;
&lt;li&gt;Install the &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapod&lt;/a&gt;&lt;/strong&gt; and create the workspace file&lt;/li&gt;
&lt;li&gt;Build each application target for each operating system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, we have created a &lt;code&gt;.podspec&lt;/code&gt; and added continuous integration for the pod as well as the example project. Lastly, we need to push the repository to GitHub and tag it with the proper version. Once that’s done, make sure you have a &lt;strong&gt;&lt;a href="https://cocoapods.org" rel="noopener noreferrer"&gt;Cocoapods&lt;/a&gt;&lt;/strong&gt; account setup and run: &lt;code&gt;pod trunk push NAME.podspec&lt;/code&gt; to push our repo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Examples and Integration &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In the end, it's important to make sure your package maintains good quality, works on its designated platforms, is easily available, and is fully tested. If you are interested, you can check out packages which I have implemented using these practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/brightdigit/Base32Crockford" rel="noopener noreferrer"&gt;Base32Crockford&lt;/a&gt;&lt;/strong&gt; - the Swift implementation of &lt;a href="https://www.crockford.com/base32.html" rel="noopener noreferrer"&gt;the Base32Crockford encoding&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/brightdigit/AssetLib" rel="noopener noreferrer"&gt;AssetLib&lt;/a&gt;&lt;/strong&gt; - which reads and updates app icon and image set information used in Xcode Asset Libraries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/brightdigit/swiftver" rel="noopener noreferrer"&gt;SwiftVer&lt;/a&gt;&lt;/strong&gt; - reads version information from Bundles and Plists as well as information stored from version control using &lt;a href="https://autorevision.github.io/" rel="noopener noreferrer"&gt;autorevision&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, you can use my GitHub template &lt;strong&gt;&lt;a href="https://github.com/brightdigit/EggSeed" rel="noopener noreferrer"&gt;EggSeed&lt;/a&gt;&lt;/strong&gt;, which automates most of what we've talked about here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creation of a Swift package library&lt;/li&gt;
&lt;li&gt;creation of Cocoapod spec&lt;/li&gt;
&lt;li&gt;setup of example projects&lt;/li&gt;
&lt;li&gt;SwiftLint and SwiftFormat tooling&lt;/li&gt;
&lt;li&gt;code documentation setup&lt;/li&gt;
&lt;li&gt;CI Integration with Travis-CI, GitHub Actions, and CodeCov.IO&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/brightdigit" rel="noopener noreferrer"&gt;
        brightdigit
      &lt;/a&gt; / &lt;a href="https://github.com/brightdigit/EggSeed" rel="noopener noreferrer"&gt;
        EggSeed
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Command Line Tool for Starting Your Swift Packages with Continuous Integration
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/brightdigit/EggSeedeggseed.svg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fbrightdigit%2FEggSeedeggseed.svg" height="150px"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/brightdigit/EggSeedword.svg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fbrightdigit%2FEggSeedword.svg" height="100px"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://swift.org" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9c38965d898bab35da85c7f1be7a1da232cb548b96595a4ce8a80b79d959696d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53504d2d4c696e7578253230253743253230694f532532302537432532306d61634f5325323025374325323077617463684f5325323025374325323074764f532d737563636573733f6c6f676f3d7377696674" alt="SwiftPM"&gt;&lt;/a&gt;
&lt;a href="http://twitter.com/leogdion" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/558df72f0738aaf8c14943be53f5ba57ac257853f3990f29827391f818e6321f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f747769747465722d406c656f6764696f6e2d626c75652e7376673f7374796c653d666c6174" alt="Twitter"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0e79642f61fdbfe664700807c814ba26a395d673a54195d99988aa70a2444cd0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f62726967687464696769742f45676753656564"&gt;&lt;img src="https://camo.githubusercontent.com/0e79642f61fdbfe664700807c814ba26a395d673a54195d99988aa70a2444cd0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f62726967687464696769742f45676753656564" alt="GitHub"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b7ed6caac0891704a15dab2a27c71be847c8190c9e057b0a1e9363ebfc5d3dc6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f62726967687464696769742f45676753656564"&gt;&lt;img src="https://camo.githubusercontent.com/b7ed6caac0891704a15dab2a27c71be847c8190c9e057b0a1e9363ebfc5d3dc6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f62726967687464696769742f45676753656564" alt="GitHub issues"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/brightdigit/EggSeed/actions?query=workflow%3AmacOS" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/brightdigit/EggSeed/workflows/macOS/badge.svg" alt="macOS"&gt;&lt;/a&gt;
&lt;a href="https://github.com/brightdigit/EggSeed/actions?query=workflow%3Aubuntu" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/brightdigit/EggSeed/workflows/ubuntu/badge.svg" alt="ubuntu"&gt;&lt;/a&gt;
&lt;a href="https://github.com/brightdigit/EggSeed/actions?query=workflow%3Aarm" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/brightdigit/EggSeed/workflows/arm/badge.svg" alt="arm"&gt;&lt;/a&gt;
&lt;a href="https://travis-ci.com/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/859afd3efce265dbe2d817ec3f1ca43f764f20696d40edddb86568ec31f382ea/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f636f6d2f62726967687464696769742f456767536565643f6c6f676f3d747261766973" alt="Travis (.com)"&gt;&lt;/a&gt;
&lt;a href="https://circleci.com/gh/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0115b0a4e38fca8d5ef188441dd2565ce9dd0debc8420beacda9553b6ed28d13/68747470733a2f2f696d672e736869656c64732e696f2f636972636c6563692f6275696c642f6769746875622f62726967687464696769742f456767536565643f6c6162656c3d78656e69616c266c6f676f3d636972636c65636926746f6b656e3d38373732383331393137643137343462313735646431643532646564393136333733663961336563" alt="CircleCI"&gt;&lt;/a&gt;
&lt;a href="https://app.bitrise.io/app/238176596b2afbd3" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/db87e2758eec424ebf10d2fb7b769702c67094a7146fbbafa9a3a7cbf3ec421a/68747470733a2f2f696d672e736869656c64732e696f2f626974726973652f323338313736353936623261666264333f6c6162656c3d6d61634f53266c6f676f3d6269747269736526746f6b656e3d645247543363716c4d53484b43393377414b30317777" alt="Bitrise"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://codecov.io/gh/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d5f4db7b2acfa378fa824c2908c12f0973ddbe0744eeefede351ef22fcc7524e/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f62726967687464696769742f45676753656564" alt="Codecov"&gt;&lt;/a&gt;
&lt;a href="https://www.codefactor.io/repository/github/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b108f246d1a7c4001bd9a8120257be4cb12bd5f8c8f44e14f280c8bb59bf77f2/68747470733a2f2f696d672e736869656c64732e696f2f636f6465666163746f722f67726164652f6769746875622f62726967687464696769742f45676753656564" alt="CodeFactor Grade"&gt;&lt;/a&gt;
&lt;a href="https://codebeat.co/projects/github-com-brightdigit-EggSeed-master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7a9e7a5269e3172ae369b9e3d66d6180e2b7a31b69eac7bb468a3a1ba4dd1d9c/68747470733a2f2f636f6465626561742e636f2f6261646765732f34663836666239302d663864652d343063352d616236332d653630363963646535303032" alt="codebeat badge"&gt;&lt;/a&gt;
&lt;a href="https://codeclimate.com/github/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b1d620902cd636a19b39321d2333f136b87dd40f6af39af7078e042b0920dc29/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636c696d6174652f6d61696e7461696e6162696c6974792f62726967687464696769742f45676753656564" alt="Code Climate maintainability"&gt;&lt;/a&gt;
&lt;a href="https://codeclimate.com/github/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c0a73dee8dcb835eb39e0db3f673792b4800638167e5809c34d0278e3e0d93d0/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636c696d6174652f746563682d646562742f62726967687464696769742f456767536565643f6c6162656c3d64656274" alt="Code Climate technical debt"&gt;&lt;/a&gt;
&lt;a href="https://codeclimate.com/github/brightdigit/EggSeed" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6c32aa3d8a71c495491a04f5dfda314558b8b6a451a4155f11ddb1756c370831/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636c696d6174652f6973737565732f62726967687464696769742f45676753656564" alt="Code Climate issues"&gt;&lt;/a&gt;
&lt;a href="https://houndci.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e21eca21daf12d42df6f064d4cf4002a00970ef0073a79921c77bcc0aa27fcc7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52657669657765645f62792d486f756e642d3845363442302e737667" alt="Reviewed by Hound"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EggSeed&lt;/strong&gt; is a command-line tool for creating swift pacakges with continous integration support. While &lt;code&gt;swift package init&lt;/code&gt;, creates simple packages, there is no guarantee that your package will work on everyone else's device. That's where &lt;em&gt;continuous integration&lt;/em&gt; goes in.&lt;/p&gt;
&lt;p&gt;By using &lt;code&gt;eggseed&lt;/code&gt;, you can create a package with full integration into CI services such as: &lt;em&gt;&lt;a href="https://github.com/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;, &lt;a href="https://travis-ci.com/" rel="nofollow noopener noreferrer"&gt;Travis-CI&lt;/a&gt;, &lt;a href="https://www.bitrise.io" rel="nofollow noopener noreferrer"&gt;BitRise&lt;/a&gt;, &lt;a href="https://circleci.com" rel="nofollow noopener noreferrer"&gt;CircleCI&lt;/a&gt;&lt;/em&gt; and more. Not only that but &lt;strong&gt;EggSeed&lt;/strong&gt; also sets up code documentation, linting, and more...&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://github.com/brightdigit/EggSeed#roadmap" rel="noopener noreferrer"&gt;roadmap below&lt;/a&gt; for more details on future integrations.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Installation&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;a href="https://github.com/yonaskolb/mint" rel="noopener noreferrer"&gt;Mint&lt;/a&gt;&lt;/h3&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;mint install brightdigit/EggSeed&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Swift Package Manager&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use as CLI&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/brightdigit/EggSeed.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; EggSeed
swift run eggseed&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Use as dependency&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add the following to your Package.swift file's dependencies:&lt;/p&gt;
&lt;div class="highlight highlight-source-swift notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;package&lt;span class="pl-kos"&gt;(&lt;/span&gt;url&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;https://github.com/brightdigit/EggSeed.git&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; from&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;0.2.0&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And then import wherever needed: &lt;code&gt;import EggSeed&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Usage&lt;/h1&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;USAGE: eggseed [--package-type &amp;lt;package-type&amp;gt;] [--user-name&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/brightdigit/EggSeed" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Additionally, badges are included from &lt;strong&gt;&lt;a href="https://shields.io" rel="noopener noreferrer"&gt;shields.io&lt;/a&gt;&lt;/strong&gt; to showcase the quality of your Swift package continuous integration.&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you have any additional questions &lt;a href="https://twitter.com/leogdion" rel="noopener noreferrer"&gt;on Twitter &lt;strong&gt;@leogdion&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://learningswift.brightdigit.com/swift-package-continuous-integration-guide/#signup" rel="noopener noreferrer"&gt;signup for the newsletter to get the latest tutorials and guides on Swift development&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>devops</category>
      <category>ios</category>
      <category>linux</category>
    </item>
    <item>
      <title>SwiftUI: Everything is possible if you think like Apple</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Mon, 02 Mar 2020 21:53:58 +0000</pubDate>
      <link>https://dev.to/leogdion/swiftui-everything-is-possible-if-you-think-like-apple-4j4o</link>
      <guid>https://dev.to/leogdion/swiftui-everything-is-possible-if-you-think-like-apple-4j4o</guid>
      <description>&lt;p&gt;SwiftUI is Apple’s new framework for building user interfaces (UI). It promises &lt;strong&gt;simplicity and consistency that's been difficult to find before now&lt;/strong&gt;. I’ve been using it for several months now, and want to explain &lt;strong&gt;how businesses with an app, or want one in 2020, can benefit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ll be covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What makes SwiftUI different.&lt;/li&gt;
&lt;li&gt;When you should use it.&lt;/li&gt;
&lt;li&gt;When you shouldn't.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8X2GVqg2lUI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this episode, Leo talks about what he's learned using SwiftUI, where he sees it's the right fit, where it's not quite ready, and some solutions to common problems people have with it.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What makes SwiftUI different?
&lt;/h2&gt;

&lt;p&gt;Before now, building a UI for an application for an Apple operating system (OS) has been a bit complicated. You often have to use various tools and frameworks. Most likely Interface Builder (for apps on iOS and MacOS) as well as UIKit (for iOS and tvOS), to build the interface you want. While these are not bad tools, they do have issues and limitations. Apple has clearly developed SwiftUI to overcome or do away these challenges altogether. &lt;/p&gt;

&lt;h3&gt;
  
  
  No more need for Storyboards or Imperative Programming
&lt;/h3&gt;

&lt;p&gt;Interface Builder is well-known for using storyboards: visual representations of the UI.  Unfortunately, storyboards don’t always accurately show what the code is doing. Storyboards do not structure information so it can be mastered or edited in one place. As a result, there is potential for misunderstanding because there’s no &lt;strong&gt;&lt;em&gt;Single Source of Truth&lt;/em&gt;&lt;/strong&gt;, a practice developers use to prevent confusion. Typically, the storyboard might not show what’s wrong if it’s not aligned with the code. For this reason, &lt;strong&gt;bug fixing becomes especially difficult&lt;/strong&gt;&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/ios-app-architecture-with-rene-cacheaux-and-josh-berlin"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;iOS App Architecture with René Cacheaux and Josh Berlin&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-ios-app-architecture-with-rene-cacheaux-and-josh-berlin" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-ios-app-architecture-with-rene-cacheaux-and-josh-berlin" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-ios-app-architecture-with-rene-cacheaux-and-josh-berlin" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-ios-app-architecture-with-rene-cacheaux-and-josh-berlin" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-ios-app-architecture-with-rene-cacheaux-and-josh-berlin"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/ios-app-architecture-with-rene-cacheaux-and-josh-berlin"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="iOS App Architecture with René Cacheaux and Josh Berlin" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This worked fine in the early years of Interface Builder and UIKit, but the UIs of our apps have now become more complex. This is a problem because UIKit relies on a style of programming called imperative programming. In this style, &lt;strong&gt;the code describes exactly how&lt;/strong&gt; the app must achieve a specific result.&lt;/p&gt;

&lt;p&gt;With SwiftUI, we do away with storyboards altogether. Rather than using imperative programming, SwiftUI uses a different style: declarative programming. &lt;strong&gt;Declarative programming expresses what the result the software must achieve, but doesn’t describe how this must be done. &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a result, SwiftUI minimizes unintended results. Additionally, the code is more flexible because it's not limited to a specific procedure.&lt;/p&gt;

&lt;h3&gt;
  
  
  SwiftUI Works for all Apple Platforms
&lt;/h3&gt;

&lt;p&gt;Tools for building Apple apps have often been limited to some, but not all, Apple platforms. Previously, it has been common to use a different Application Programming Interface (API) for each device. However, with SwiftUI, everything is in Swift and shared across all devices. As a result, &lt;strong&gt;it is possible to create an interface with a single API that works on all Apple platforms, from the Mac to the Apple Watch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SwiftUI has a big advantage over other frameworks because you can build a complete UI with just SwiftUI using only one programming language. This is possible because SwiftUI works in Apple’s latest development environment, XCode 11.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/wwdc-2019-swift-ui-with-jason-anderson"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;WWDC 2019 - Swift UI with Jason Anderson&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-wwdc-2019-swift-ui-with-jason-anderson" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-wwdc-2019-swift-ui-with-jason-anderson" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-wwdc-2019-swift-ui-with-jason-anderson" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-wwdc-2019-swift-ui-with-jason-anderson" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-wwdc-2019-swift-ui-with-jason-anderson"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/wwdc-2019-swift-ui-with-jason-anderson"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="WWDC 2019 - Swift UI with Jason Anderson" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  What SwiftUI is good for?
&lt;/h2&gt;

&lt;p&gt;As a result of the above, there are some clearly good uses for SwiftUI:&lt;/p&gt;

&lt;h3&gt;
  
  
  Apps with simple or cross-platform interfaces
&lt;/h3&gt;

&lt;p&gt;As part Xcode 11, you can use a lot of design tools with SwiftUI, including being able to drag-and-drop visual elements. If you need a simple UI and don’t need custom functions, SwiftUI will probably work perfectly for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SwiftUI is really great for the Apple Watch, which is coming into its own now.&lt;/strong&gt; Since the Watch requires a simple UI, SwiftUI is an excellent choice because it will not only work natively but will work with any other Apple OS too.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Apps
&lt;/h3&gt;

&lt;p&gt;If you’re going to build an app on for any Apple platform, you might as well start using SwiftUI. You will have all the functionality that Apple is able to provide within a single framework*&lt;em&gt;. This also goes for anyone with an app who wants to migrate it to other Apple systems.&lt;/em&gt;*&lt;/p&gt;

&lt;h3&gt;
  
  
  For Tech-Savvy Users Using the Latest Apple Products
&lt;/h3&gt;

&lt;p&gt;SwiftUI is a good choice for apps designed for tech-savvy users who are using the latest Apple OS's, like iOS 13. The reason is Apple has developed SwiftUI to take advantage of the latest functionality. This includes things like Apple’s improvements to UI design, UI transitions, animations, and how Dark Mode works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3u6SrJU1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/02/xcode-lansing-codes.png%3Ffit%3D640%252C360%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3u6SrJU1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/brightdigit.com/wp-content/uploads/2020/02/xcode-lansing-codes.png%3Ffit%3D640%252C360%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/brightdigit/lansingcodes-apple"&gt;&lt;em&gt;SwiftUI being used to build an app for local developer meetups in Lansing&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When is SwiftUI not a good choice?
&lt;/h2&gt;

&lt;p&gt;That all said, SwiftUI is not always the right choice. There are a few instances where you’re either going to need something else, or you’re not going to see the benefits:&lt;/p&gt;

&lt;h3&gt;
  
  
  Older Apps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;If you’re using an app that’s more than a few years old and still supports older Apple OS's,  you’re not likely to see any real benefit.&lt;/strong&gt; There’s nothing your users will really see or appreciate. You’re probably better off sticking with UIKit or whatever framework you’re using.&lt;/p&gt;

&lt;p&gt;It’s worth mentioning a downside of using SwiftUI right now: there’s very little documentation. Because it's still so new, we’re still spending a lot of time figuring out how everything works and how to use it. &lt;strong&gt;For now, this means there is significant learning time if you want to develop with it.&lt;/strong&gt; For an older app, you’re not likely to see a great return on investment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Users using Older Operating Systems or Devices
&lt;/h3&gt;

&lt;p&gt;Related to the above, one of the limitations of SwiftUI is it will only work with the latest Apple operating systems. It has no legacy compatibility. If you have users with older Apple products or who take a long time to update things, they are either going to struggle or simply not be able to use your new UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apps that need to be Android-compatible
&lt;/h3&gt;

&lt;p&gt;Finally, SwiftUI isn't going to help with apps that need to work on non-Apple systems. Swift is only used by Apple and SwiftUI only works in Swift. Therefore, you’ll need a different framework if you want your app to work on Android, Windows, or a website.&lt;/p&gt;

&lt;p&gt;I generally recommend not building these kinds of apps anyway, as they rarely deliver the experience that a native app can. &lt;strong&gt;I’ve talked about this on &lt;a href="https://brightdigit.com/blog/2019/07/17/empowerapps-show-cross-platform-comparison-with-rob-kerr/"&gt;my podcast&lt;/a&gt; and &lt;a href="https://brightdigit.com/blog/2019/10/18/native-app-development-advantages/"&gt;my blog&lt;/a&gt; if you’re interested in learning more.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2020 is going to be an interesting year for Apple apps
&lt;/h2&gt;

&lt;p&gt;SwiftUI is likely going to make building apps for Apple products easier going forward. Especially if you’re comfortable working within the limits of Apple’s new framework. I think the people at Apple were thoughtful with this new framework and it will help create better interfaces for users.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about SwiftUI, &lt;strong&gt;check out &lt;a href="https://learningswift.brightdigit.com/tag/swiftui/"&gt;my Swift developer blog&lt;/a&gt;&lt;/strong&gt; as well as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/tutorials/swiftui/"&gt;Apple's SwiftUI Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thatthinginswift.com/should-you-use-swiftui-in-your-app/"&gt;Should you write your app in SwiftUI by Nick O'Neill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rambo.codes/swiftui/2020/01/03/you-can-use-swiftui-today.html"&gt;You can use SwiftUI today By Gui Rambo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://heckj.github.io/swiftui-notes/"&gt;Using Combine by Joseph Heck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackingwithswift.com/100/swiftui"&gt;100 Days of SwiftUI by Paul Hudson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goshdarnswiftui.com"&gt;Gosh Darn SwiftUI by Sarun Wongpatcharapakorn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.donnywals.com/understanding-combines-publishers-and-subscribers/"&gt;Understanding Combine’s publishers and subscribers By Donny Wals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swiftwithmajid.com/2019/11/27/combine-and-swiftui-views/"&gt;Combine and SwiftUI views by Majid Jabrayilov&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re interested in keeping up to date with what’s new for iOS and Apple development, I invite you to &lt;a href="https://brightdigit.com/subscribe/"&gt;sign up for my newsletter&lt;/a&gt;. I will let you know when I put out new content and if there are important things you should know when it comes to creating or updating your apps.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>architecture</category>
      <category>swiftui</category>
    </item>
    <item>
      <title>Asynchronous Multi-Threaded Parallel World of Swift</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Tue, 01 Oct 2019 18:06:05 +0000</pubDate>
      <link>https://dev.to/leogdion/asynchronous-multi-threaded-parallel-world-of-swift-4gjh</link>
      <guid>https://dev.to/leogdion/asynchronous-multi-threaded-parallel-world-of-swift-4gjh</guid>
      <description>&lt;p&gt;Over the last 15 years, CPU clock rate has plateaued due to thermal limitations in processors. As a result, CPU manufactures have instead chosen to add more cores or processing units. &lt;strong&gt;Therefore nearly every device has multiple cores: from a Mac Pro to the Apple Watch.&lt;/strong&gt; For this reason, Swift developers should take advantage of asynchronous methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mXmKMsBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/GraphOfCPUSpeed.001-e1569273003542-1024x657.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mXmKMsBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/GraphOfCPUSpeed.001-e1569273003542-1024x657.jpg" alt="Graph of CPU Speed from 1970 to 2020"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is to say, with asynchronous methods, &lt;strong&gt;we can design applications which take advantage of multiple cores and deliver a better user experience.&lt;/strong&gt; Therefore, let’s discuss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding Parallelism, Concurrency, and Asynchronous&lt;/li&gt;
&lt;li&gt;How Operating Systems Breakdown Operations&lt;/li&gt;
&lt;li&gt;Situations Swift Developers Run Into&lt;/li&gt;
&lt;li&gt;Discrete APIs&lt;/li&gt;
&lt;li&gt;Working with Queues&lt;/li&gt;
&lt;li&gt;Dealing with Promises and Futures&lt;/li&gt;
&lt;li&gt;Subscribers and Publishers with Combine&lt;/li&gt;
&lt;li&gt;The Future with Coroutines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Concepts&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;First, we need to understand how operating systems handle tasks and how they can schedule them efficiently. As an example, lets look at the two independent operations. In this case, we have a pink one which is processing image A and a blue one which is processing image B.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrency and Parallelism
&lt;/h3&gt;

&lt;p&gt;When these operations are scheduled by the operating system, they can be run &lt;em&gt;concurrently&lt;/em&gt;. &lt;strong&gt;Concurrency&lt;/strong&gt; means that the operation can be partitioned and run at the same time on the same processor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--orob56V4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/ParallelConcurrency.001-1024x768.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--orob56V4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/ParallelConcurrency.001-1024x768.jpeg" alt="The Difference Between Concurrency and Parallelism"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition, when the operating system has access to multiple processing units or cores, it can also run the operations in &lt;strong&gt;parallel&lt;/strong&gt;. To put it differently both operations can be run on separate processing units. In essence, &lt;strong&gt;Parallelism&lt;/strong&gt; differs from &lt;strong&gt;concurrency&lt;/strong&gt; in that &lt;strong&gt;concurrency&lt;/strong&gt; partitions each operation in order to continue different operations. Therefore, &lt;strong&gt;concurrency&lt;/strong&gt; can be applied to a single processing unit. Conversely, &lt;strong&gt;Parallelism&lt;/strong&gt; can only be applied to multiple processing units. Moreover, &lt;strong&gt;concurrency&lt;/strong&gt; and &lt;strong&gt;parallelism&lt;/strong&gt; can be applied at the same time by the operating system. Most importantly for developers is to make our operations &lt;strong&gt;asynchronous&lt;/strong&gt;, in order to allow for &lt;strong&gt;concurrency&lt;/strong&gt; and &lt;strong&gt;parallelism.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RoCm8aal--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/The-Multi-Threaded-Asynchronous-Parallel-World-of-Swift-360iDev-copy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RoCm8aal--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/The-Multi-Threaded-Asynchronous-Parallel-World-of-Swift-360iDev-copy.gif" alt="Replacing A Single Synchronous Operation with an Asynchronous Operation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous Operations
&lt;/h3&gt;

&lt;p&gt;There are long operations, such as network requests, which are not well suited for standard synchronous operations. That is to say, by programming these calls synchronously, it will lock up other active operations such as user interface updates. Therefore making these calls asynchronous allows for other operations to be run concurrently. Specifically this is done in Swift, by including a completion closure or code block as a parameter. To put it differently, when the operation is completed that closure is executed on completion with a result passed.&lt;/p&gt;

&lt;p&gt;For instance rather than actively waiting for a download to complete, the API allows the developer to pass what code they want the application to run when the operation is completed. Notably, this allows the operating system to schedule other operations in meantime like updating your UI. With this in mind, let’s take a look at the several ways Swift developers already run into this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do we run into asynchronous operations? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Swift developers are already taking advantage of concurrency with asynchronous functions in their applications. Primary there are three APIs we commonly see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network Requests&lt;/li&gt;
&lt;li&gt;NotificationCenter&lt;/li&gt;
&lt;li&gt;Timers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network Requests and URLSession
&lt;/h3&gt;

&lt;p&gt;Network requests are the most frequent example where asynchronous calls make the most sense. While the developer can call a &lt;code&gt;Data&lt;/code&gt; constructor to pull contents from a url, Apple already provides an asynchronous method to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;url&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://jaspervdj.be/lorem-markdownum/markdown.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;url&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;response&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="o"&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, a &lt;code&gt;URLSessionDataTask&lt;/code&gt; is created with a callback which takes in the binary &lt;code&gt;Data&lt;/code&gt;, the &lt;code&gt;URLResponse&lt;/code&gt;, and possible &lt;code&gt;Error&lt;/code&gt;. The API will handle the buffering of data and calculating when the request is complete. Additionally it will do it as a separate operation. As a result, the operating system can run other operations concurrently. Likewise &lt;code&gt;NotificationCenter&lt;/code&gt; does this as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  NotificationCenter
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&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;url&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;response&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="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notificationDownloaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;object&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="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="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notificationDownloaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;object&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&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;"Notification Sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finishExecution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needsIndefiniteExecution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, when the download is complete, the application posts a notification to &lt;code&gt;NotificationCenter&lt;/code&gt;. Additionally, theres an observer for the notification. Therefore, once the notification is received the Playground prints a message and finishes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timers
&lt;/h3&gt;

&lt;p&gt;The application can take this further by adding a &lt;code&gt;Timer&lt;/code&gt;, another asynchronous operation. &lt;code&gt;Timer&lt;/code&gt; allows developers to delay or periodically repeat an operation. Once again, the API takes advantage of concurrency rather than locking up the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notificationDownloaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;object&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&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;"Notification Received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kt"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduledTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;withTimeInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;repeats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&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;"Timer Activated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finishExecution&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;In this example, the code doesn't print the message as before. Rather, a &lt;code&gt;Timer&lt;/code&gt; is initialized with a 1 second delay. Therefore when the time approaches, the Playground prints the message and completes.&lt;/p&gt;

&lt;p&gt;Although these asynchronous abstraction offer a convenient way to optimize your applications, there are problems which do come up. Primarily on iOS, the developer isn't able to prioritize each operation. As a result, this is most noticeable is when the developer attempts to update the user interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous UI Updating with the Main Queue
&lt;/h3&gt;

&lt;p&gt;One of the first lessons, developers learn when developing for the iPhone or iPad is necessity to make user interface updates on the main thread or &lt;code&gt;DispatchQueue&lt;/code&gt;. Whether it’s simply updating a &lt;code&gt;UILabel&lt;/code&gt; or a &lt;code&gt;UITableViewCell&lt;/code&gt;, the UI update needs to be on the main &lt;code&gt;DispatchQueue&lt;/code&gt;. Therefore, the operation needs to &lt;em&gt;hop&lt;/em&gt; to another queue in order to complete the update to the user interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;timerSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeTimerSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&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="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;timerSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setEventHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Timer Activated"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;timerSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kt"&gt;NotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notificationDownloaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;object&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&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;"Notification Received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;timerSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;activate&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;In this example, &lt;code&gt;DispatchSourceTimer&lt;/code&gt; is created. &lt;code&gt;DispatchSourceTimer&lt;/code&gt; is similar to &lt;code&gt;Timer&lt;/code&gt;, however the developer has more control over the priority and the queue. As with the previous &lt;code&gt;Timer&lt;/code&gt;, when the &lt;code&gt;Notification&lt;/code&gt; is observed, the &lt;code&gt;Timer&lt;/code&gt; is started with a 1 second delay. However since the &lt;code&gt;DispatchSourceTimer&lt;/code&gt; is designated for using the &lt;code&gt;global&lt;/code&gt; queue, it is nessecary to &lt;em&gt;hop&lt;/em&gt; to the &lt;code&gt;main&lt;/code&gt; &lt;code&gt;DispatchQueue&lt;/code&gt; and update a &lt;code&gt;UILabel&lt;/code&gt; with the text &lt;em&gt;Timer Activated&lt;/em&gt;. Consequently if this is not done, the user interface will not update correctly. Before I explain further how &lt;code&gt;DispatchQueue&lt;/code&gt; and &lt;em&gt;Grand Central Dispatch&lt;/em&gt; works, let’s breakdown how operating systems schedule operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YGF-wXKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/Screen-Shot-2019-09-24-at-2.04.19-PM.png%3Ffit%3D640%252C438%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YGF-wXKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/Screen-Shot-2019-09-24-at-2.04.19-PM.png%3Ffit%3D640%252C438%26ssl%3D1" alt="An example of the top command view of processes and threads"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Operating Systems Handle Operations&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Operating System have two level of controlling operations: Processes and Threads. A process is a running instance of an application such as this running instance of &lt;em&gt;Activity Monitor&lt;/em&gt; listing out actual processes_:_&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MvA2fVvc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/Screen-Shot-2019-09-23-at-5.30.47-PM.png%3Ffit%3D640%252C414%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvA2fVvc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/Screen-Shot-2019-09-23-at-5.30.47-PM.png%3Ffit%3D640%252C414%26ssl%3D1" alt="List of Processes Running In Activity Monitor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moreover, a developer can breakdown a process into &lt;strong&gt;threads&lt;/strong&gt;. A &lt;strong&gt;thread&lt;/strong&gt; is a small sequence of instructions within a process which the operating system can schedule individually. In other words, a developer can breakdown a running application into parts which give the operating system more leeway in scheduling tasks.&lt;/p&gt;

&lt;p&gt;Therefore, let's discuss the various ways developers can organize individuals operations in Swift. Firstly let's discuss the most direct control of threads and processes and slowly evolve into the more abstract and easy to manage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---4em-nOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/493303884_5c71fbcefb_o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---4em-nOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/493303884_5c71fbcefb_o.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Original Apple APIs &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Over the years, Apple has evolved its API for giving developers control over their operations and their scheduling. At first, the API was pretty basic and direct but has become increasing developer-friendly and given more control to the operating system as to how to manage it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Thread Class
&lt;/h4&gt;

&lt;p&gt;Although this may be true, let's start by at least touching upon that most direct API: &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/foundation/thread"&gt;Thread&lt;/a&gt;&lt;/strong&gt; (or NSThread in Objective-C). The Thread class gives the developer direct access to creating actual threads. Their are two ways to do this: pass in a closure to the initializer or subclass and override the &lt;em&gt;main&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;Although this API is available, I would recommend against using it unless you absolutely have to. As you'll see, there are better abstractions which give better control to the operating system and are easy to maintain for the developer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Process Class (for macOS only)
&lt;/h4&gt;

&lt;p&gt;However there are occasions on the Mac, where you need to run a command or external application. In that case it's best to use &lt;a href="https://developer.apple.com/documentation/foundation/process"&gt;the&lt;/a&gt; &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/foundation/process"&gt;Process&lt;/a&gt;&lt;/strong&gt; &lt;a href="https://developer.apple.com/documentation/foundation/process"&gt;class&lt;/a&gt; (or NSTask in Objective-C). With the Process class, you provide a url to the executable and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executableURL&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;fileURLWithPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/bin/ls"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;terminationHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finishExecution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While directly creating threads takes control away from the API and operating system, I think this is perfectly reasonable. In instances where a piece of functionality is already available on macOS running another outside process makes sense. As with many operations, it is important to make sure it does not interfere with the user experience. While there's the function &lt;code&gt;waitUnitExit&lt;/code&gt; in order which provides a synchronous result from the operation, using the property &lt;code&gt;terminationHandler&lt;/code&gt;, allows for asynchronous callback. That is to stay, using &lt;code&gt;terminationHandler&lt;/code&gt; allows the application to do other operation as it waits for that process to finish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m3ccQM_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/1o77vgbvkxq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m3ccQM_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/1o77vgbvkxq.jpg" alt="An example of people in a queue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with Queues and Asynchronous Operations &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;While the Process and Thread class gives developers direct control, Apple has introduced more abstract ways of dealing with operations. At the top of those abstraction is the all important &lt;strong&gt;Grand Central Dispatch.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Grand Central Dispatch
&lt;/h4&gt;

&lt;p&gt;Grand Central Dispatch is by far the most used API for dealing with parallelism and concurrency through asynchronous operations. Specially, the most important class in that API is the &lt;strong&gt;DispatchQueue&lt;/strong&gt; class. DispatchQueue allows for the developer to control the scheduling of operations. Additionally, the developer can guide some more abstract aspects regarding how the operating system organizes the operations.&lt;/p&gt;

&lt;p&gt;For instance, if we were to count from 0 to 1000 within a Playground in two different DispatchQueues: the high-priority main queue and the lower-priority global queue, the code would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needsIndefiniteExecution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&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;repeat&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;"glob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;value&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;repeat&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;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kt"&gt;PlaygroundPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finishExecution&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;By doing this, we would see the counting for each queue interleaved with each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
main 947
glob 814
glob 815
main 948
glob 816
main 949
glob 817
main 950
glob 818
main 951
glob 819
main 952
main 953
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the example above the developer can control the priority or queue of the code block, however there are more ways we can control the DispatchQueue through the use of flags, quality of service and attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;barrierQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"barrier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="n"&gt;barrierQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;markdownFiles&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;text&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;As we can see, we've created our own DispatchQueue and noted that it is &lt;em&gt;concurrent&lt;/em&gt;. In other words, while the each operation we add is run in order, the following operation will not wait for the previous operation to complete. What must be remembered is that running multiple operations concurrently can result in what's called a &lt;strong&gt;Race Condition&lt;/strong&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Dealing with Race Conditions in GCD
&lt;/h5&gt;

&lt;p&gt;A Race Condition is where multiple operations are dependent on a single changeable object or variable resulting in the possibility in an error. For instance here's an example of a Race Condition issue using the Thread class API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;increaseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;max&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;next&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;repeat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forTimeInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;items&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;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;max&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;As a result of running this in two separate threads, we could get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
2
3
4
5
6
7
8
9
10
10 // 😱 Oh No! 😱 
11 // 😢
11 // 😭
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Luckily Grand Central Dispatch provides two ways of resolving this through barriers: semaphores and flags.&lt;/p&gt;

&lt;h6&gt;
  
  
  Semaphores in GCD
&lt;/h6&gt;

&lt;p&gt;A great use of the DispatchSemaphore is in the Thread example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;semaphore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchSemaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&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="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;increaseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;max&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;next&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;repeat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;semaphore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kt"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forTimeInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;items&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;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;semaphore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;max&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;In this example, we are more or less locking down the reading and writing to the array so it only can be executing by one thread at a time. In other words, the operation between &lt;code&gt;.wait()&lt;/code&gt; and &lt;code&gt;.signal()&lt;/code&gt; is executing &lt;em&gt;atomically&lt;/em&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  Barriers using DispatchWorkItemFlags
&lt;/h6&gt;

&lt;p&gt;In contrast, with a DispatchQueue, we can provide a flag to ensure the &lt;code&gt;markdownFiles&lt;/code&gt; is accessed &lt;em&gt;atomically&lt;/em&gt;, we can use the &lt;code&gt;.barrier&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;barrierQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"barrier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="n"&gt;barrierQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;group&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="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;barrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;markdownFiles&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;text&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;h5&gt;
  
  
  Organizing Multiple Operations with DispatchGroup
&lt;/h5&gt;

&lt;p&gt;Besides DispatchQueue another great use of Grand Central Dispatch is &lt;strong&gt;DispatchGroup&lt;/strong&gt;. For instance, if you have multiple asynchronous operations which are not dependent on each other such multiple url calls, DispatchGroup is perfect. DispatchGroup allows the developer to track their asynchronous completion as a whole:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;markdownFiles&lt;/span&gt; &lt;span class="o"&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="nv"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&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;index&lt;/span&gt; &lt;span class="nf"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;markdownFiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
      &lt;span class="k"&gt;try!&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;contentsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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;In the example above, we create a DispatchGroup. Next, the code asynchronously downloads 20 markdown files and sets the result in the array. Markedly, each time &lt;code&gt;group.enter()&lt;/code&gt; is called when the process starts and &lt;code&gt;group.leave()&lt;/code&gt; is called to note that particular operation is completed. Lastly, the developer can call either &lt;code&gt;[notify](https://developer.apple.com/documentation/dispatch/dispatchgroup/2016084-notify)&lt;/code&gt; or &lt;code&gt;[wait](https://developer.apple.com/documentation/dispatch/dispatchgroup/1780590-wait)&lt;/code&gt; on the DispatchGroup depending on whether to wait asynchronously or synchronously.&lt;/p&gt;

&lt;p&gt;One of the more complex natures of multiple asynchronous operations is organizing dependencies. Therefore let's discuss the next level of abstraction which specialized in dependencies - OperationQueues.&lt;/p&gt;

&lt;h4&gt;
  
  
  Operation Queues
&lt;/h4&gt;

&lt;p&gt;An older yet more abstract API for dealing with multiple Operations is the OperationQueue (or NSOperationQueue in Objective-C). A preferred method for dealing with operations, OperationQueues are fairly to simple to get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;operation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BlockOperation&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;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;100&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="n"&gt;index&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="kt"&gt;OperationQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, we simply add a BlockOperation to the main queue and it will automatically start printing out 1 to 100. Most importantly, its with dependencies where OperationQueue shows their potential:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;operation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BlockOperation&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;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;100&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="n"&gt;index&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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;anotherOperation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BlockOperation&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;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="mi"&gt;200&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="n"&gt;index&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;anotherOperation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;OperationQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anotherOperation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;OperationQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above example, we add a dependency of one operation (0...100) to another (101...200) to ensure that the counting is in the correct order. As a result, regardless of the order of how the operations are added, dependent operation is executed first. For this reason, the developer can add operations in whatever fashion as long as their dependencies are setup beforehand.&lt;/p&gt;

&lt;h5&gt;
  
  
  Problems with OperationQueue
&lt;/h5&gt;

&lt;p&gt;While dependency management is easier with OperationQueues, there a couple of issues which showcase it's dated Objective-C outlook. Firstly, there is no native method for doing asynchronous operations in the Operation (or BlockOperation) class. In other words, the developer must subclass the Operation and optimize the code for asynchronous operations or convert the underlying method to an synchronous method. Secondly, there is no native way to deal with results or errors of each operation. Therefore, the developer must handle the result of each operation outside of the operation.&lt;/p&gt;

&lt;p&gt;Instead a more modern and functional method for handling asynchronous methods and their results or errors comes in the form of Promises and Futures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t4pf_IWc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/zolfyh_ygpw-e1569349209279.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t4pf_IWc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/zolfyh_ygpw-e1569349209279.jpg" alt="A Rainbow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Promises and Futures of Better Asynchronous APIs &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;While Apple provides some abstractions for asyncronous operations, Swift developer will often run into the dreaded &lt;em&gt;callback hell&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;doThis&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;thenThis&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;andThenThis&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;lastlyThis&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="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This awful mess of code can be difficult to manage especially when catching error and dealing with various logic. As much as closures are superior to Objective-C code blocks, other programming languages such as JavaScript and C# have improved on this with the concept of &lt;em&gt;promises&lt;/em&gt; and &lt;em&gt;futures&lt;/em&gt;. In short, where a synchronous function returns a value, this abstraction allows for the returning of a &lt;em&gt;promised future&lt;/em&gt; value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;thatPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doThis&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;let&lt;/span&gt; &lt;span class="nv"&gt;thenThisPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thatPromise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thenThis&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;andThenThisPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thenThisPromise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;andThenThis&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;lastPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;andThenThisPromise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastlyThis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Therefore, let’s take a look at a couple of Swift libraries: SwiftNIO and Google’s Promise library.&lt;/p&gt;

&lt;h3&gt;
  
  
  SwiftNIO - Asynchronous on the Server
&lt;/h3&gt;

&lt;p&gt;While Swift's largest focus has been on the iPhone, it is important to note that the server is where asynchronous operations often occur. Whether the server is making HTTP calls to the outside or accessing a database, it has to wait for the completion of network requests. Therefore, it’s no wonder that SwiftNIO the backbone of the main server-side frameworks, Kitura and Vapor, employs its own Promise and Future infrastructure. While server-side Swift mostly uses SwiftNIO, Apple devices such as the iPhone can also use the package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;withTheme&lt;/span&gt; &lt;span class="nv"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;completed&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;Error&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;withTheme&lt;/span&gt; &lt;span class="nv"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="nv"&gt;eventLoop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EventLoop&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;EventLoopFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;&amp;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;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makePromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&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="n"&gt;eventLoop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&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="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fail&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futureResult&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, there is an asynchronous function which sets up a website based on a theme. Namely, this function takes as parameters, the site, the theme, and a closure which takes in an &lt;code&gt;Error&lt;/code&gt; if the operation failed. Given that, for the purpose of using Futures, there is a new method which returns SwiftNIO’s &lt;code&gt;Future&lt;/code&gt; or &lt;code&gt;EventLoopFuture&lt;/code&gt; with the resulting &lt;code&gt;Site&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Notably, in Swift, some sort of queue, thread, or loop must be specified in order to assign where the operation will be executed. Likewise, SwiftNIO uses the &lt;code&gt;EventLoop&lt;/code&gt; to designate where the operation will be executed. Therefore, from the &lt;code&gt;EventLoop&lt;/code&gt;, an &lt;code&gt;EventLoopPromise&lt;/code&gt; is created. Next, from the &lt;code&gt;EventLoop&lt;/code&gt; a closure is passed where the original asynconous &lt;code&gt;setupSite&lt;/code&gt; function is called. From inside the closure, a success or failure state on the promise is set using &lt;code&gt;.fail&lt;/code&gt; and &lt;code&gt;.succeed&lt;/code&gt;. Lastly, the promise has a property which contains the &lt;em&gt;future&lt;/em&gt; using &lt;code&gt;.futureResult&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;using&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eventLoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whenComplete&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In most cases, the &lt;code&gt;EventLoop&lt;/code&gt; is accessed from originating &lt;code&gt;HTTPRequest&lt;/code&gt; or &lt;code&gt;Application&lt;/code&gt;. In any case, to call our &lt;code&gt;Future&lt;/code&gt; returning function and do something with the value, &lt;code&gt;whenComplete&lt;/code&gt; to set the callback on the resulting operation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Functional Programming in SwiftNIO
&lt;/h4&gt;

&lt;p&gt;The other advantage of &lt;em&gt;promises&lt;/em&gt; and &lt;em&gt;futures&lt;/em&gt;, is being able to apply functional programming concepts to &lt;em&gt;future&lt;/em&gt; results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;futureSite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;using&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eventLoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// returns a Future&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;futureString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// flatMap "flattens" the Future&amp;lt;Future&amp;lt;String&amp;gt;&amp;gt; to just&lt;/span&gt;
&lt;span class="c1"&gt;// Future&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;futureHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// return Future&amp;lt;String&amp;gt;&lt;/span&gt;
   &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fromAsyncLoadingSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&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;sites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// flatten "flattens" [Future&amp;lt;String&amp;gt;] to Future&amp;lt;[String]&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;siteNamesFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;using&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eventLoop&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;nameAndHTML&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureString&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureHTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Therefore, with SwiftNIO:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.map&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;converts &lt;code&gt;Future&amp;lt;A&amp;gt;&lt;/code&gt; to &lt;code&gt;Future&amp;lt;B&amp;gt;&lt;/code&gt; by&lt;/li&gt;
&lt;li&gt;taking in a closure of type: &lt;code&gt;(A) -&amp;gt; (B)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.flatMap&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;converts &lt;code&gt;Future&amp;lt;A&amp;gt;&lt;/code&gt; to &lt;code&gt;Future&amp;lt;B&amp;gt;&lt;/code&gt; by&lt;/li&gt;
&lt;li&gt;taking in a closure of type: &lt;code&gt;(A) -&amp;gt; (Future&amp;lt;B&amp;gt;)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.flatten&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;converts &lt;code&gt;[Future&amp;lt;A&amp;gt;]&lt;/code&gt; to &lt;code&gt;Future&amp;lt;[A]&amp;gt;&lt;/code&gt; by&lt;/li&gt;
&lt;li&gt;taking in an &lt;code&gt;EventLoop&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.and&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;on &lt;code&gt;Future&amp;lt;A&amp;gt;&lt;/code&gt; and takes in a &lt;code&gt;Future&amp;lt;B&amp;gt;&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;B&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;returns a &lt;code&gt;Future&lt;/code&gt; tuple of type &lt;code&gt;Future&amp;lt;(A,B)&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Unfortunately since network operation and server-side communication are at the center of SwiftNIO, the only way currently to create an &lt;code&gt;EventLoop&lt;/code&gt; on iOS is by using a &lt;code&gt;MultithreadedEventLoopGroup&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MultiThreadedEventLoopGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;numberOfThreads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&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;eventLoop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, a better library to implement &lt;em&gt;promises&lt;/em&gt; on iOS (and other client devices) is Google’s own &lt;em&gt;Promise&lt;/em&gt; framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/google/promises"&gt;Google Promise&lt;/a&gt; - Asynchronous on the Client
&lt;/h3&gt;

&lt;p&gt;While Apple makes SwiftNIO and it contains a great implementation of &lt;em&gt;Futures&lt;/em&gt; and &lt;em&gt;Promises&lt;/em&gt;, it is focuses on server-side and networking related implementation. However, on the client, Google Promises might be amongst the best &lt;em&gt;Promise&lt;/em&gt; APIs for Swift.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;withTheme&lt;/span&gt; &lt;span class="nv"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt; &lt;span class="o"&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&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;failure&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="p"&gt;}&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;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&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="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While SwiftNIO required the proprietary &lt;code&gt;EventLoop&lt;/code&gt;, &lt;strong&gt;Google Promises&lt;/strong&gt; requires the familiar &lt;code&gt;DispatchQueue&lt;/code&gt;. Therefore to create a &lt;code&gt;Promise&lt;/code&gt; oriented version of &lt;code&gt;setupSite&lt;/code&gt;, the function needs a &lt;code&gt;DispatchQueue&lt;/code&gt; parameter and needs to return a &lt;code&gt;Promise&lt;/code&gt; on that &lt;code&gt;DispatchQueue&lt;/code&gt; with a closure that calls either &lt;code&gt;success&lt;/code&gt; or &lt;code&gt;failure&lt;/code&gt; depending on the result. Therefore to call the method, the code needs to pass a &lt;code&gt;DispatchQueue&lt;/code&gt; and on the &lt;code&gt;Promise&lt;/code&gt; call &lt;code&gt;.then&lt;/code&gt; to use the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;futureSite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;on&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="c1"&gt;// returns a Promise&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;futureString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// returns a Promise&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;futureHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// return Promise&amp;lt;String&amp;gt;&lt;/span&gt;
   &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fromAsyncLoadingSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&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;sites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// `all` "flattens" [Promise&amp;lt;String&amp;gt;] to Future&amp;lt;[Promise]&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;siteNamesFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;     
  &lt;span class="p"&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;nameAndHTML&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;futureHTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Functional Programming in Google Promise
&lt;/h4&gt;

&lt;p&gt;Additonally while SwiftNIO differentiated &lt;code&gt;.map&lt;/code&gt;, &lt;code&gt;.flatMap&lt;/code&gt;, and &lt;code&gt;.whenComplete&lt;/code&gt;, &lt;strong&gt;Google Promise&lt;/strong&gt; simplifies it into &lt;code&gt;.then&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.then&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;converts &lt;code&gt;Promise&amp;lt;A&amp;gt;&lt;/code&gt; to &lt;code&gt;Promise&amp;lt;B&amp;gt;&lt;/code&gt; by&lt;/li&gt;
&lt;li&gt;taking in a closure of type:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(A) -&amp;gt; (B)&lt;/code&gt; or&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(A) -&amp;gt; (Promise&amp;lt;B&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;all&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;converts &lt;code&gt;[Promise&amp;lt;A&amp;gt;]&lt;/code&gt; to &lt;code&gt;Promise&amp;lt;[A]&amp;gt;&lt;/code&gt; or&lt;/li&gt;
&lt;li&gt;converts &lt;code&gt;(Promise&amp;lt;A&amp;gt;, Promise&amp;lt;B&amp;gt;, …)&lt;/code&gt; into &lt;code&gt;Promise&amp;lt;(A,B,…)&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Additionally, Google Promises also has a specific method for dealing with Error or failure states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.catch&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;Void&lt;/code&gt; method which takes a closure of type: &lt;code&gt;(Error) -&amp;gt; Void&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;As a result to fulfill a &lt;code&gt;Promise&lt;/code&gt;, use either &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; or &lt;code&gt;fulfill&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;on&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="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fulfill&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// on success&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// on error&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However while &lt;em&gt;Promises&lt;/em&gt; and &lt;em&gt;Future&lt;/em&gt; are certainly a better way to avoid &lt;em&gt;callback hell&lt;/em&gt;, there are recent updates which emphasis the important of user interface responsive. That is to say rather functional emphasis on optimal operations, this emphasizes the reactive nature of UI development: &lt;strong&gt;Combine&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Combine-ing It All Together &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;SwiftUI&lt;/strong&gt;, Apple has snuck in a whole other framework for managing asynchronous tasks: &lt;strong&gt;Combine&lt;/strong&gt;. With &lt;strong&gt;Combine&lt;/strong&gt;, Apple is introducing an asynchronous model more reflecting the Subscriber-Publisher model used in reactive programming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactive UI Focused Asynchronous Operations
&lt;/h3&gt;

&lt;p&gt;While Promises and Futures handle how to deal with the results of asynchronous operations, Combine focuses on reacting to multiple changes in multiple locations. For instance, a Publisher issues changes to data and a Subscriber listens to the those changes. Therefore SwiftUI becomes the ideal use case for using Combine with data changes. For instance, if we have a SwiftUI View which displays the header from a downloaded markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;ContentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;nameObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContentObject&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nameObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;In this case, this SwiftUI View contains a ObservedObject with a name property, which is the name or header of the ContentObject. Therefore, let’s take a look at the content object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ContentObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&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;publisher&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellable&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&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="o"&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;willSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;objectWillChange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;static&lt;/span&gt; &lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;markdownTitlePublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fromURL&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ContentObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;markdownTitlePublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fromURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContentObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancellable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&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="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContentObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&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;In this instance, there is an initializer which creates the publisher for the markdown file’s &lt;code&gt;h1&lt;/code&gt; name . Inside the initializer, we create a publisher for the name, followed by setting up the assignment of the result to the name property. Firstly, it creates the publisher. Next, similar to before with UIKit updates, the code tells the publisher that it must receive the changes on the main DispatchQueue. Lastly, it tells the publisher to assign the value to the name property on self. With the initializer, the code has setup the publisher for the &lt;code&gt;name&lt;/code&gt; of the content, a cancellable for the publisher assignment, and the &lt;code&gt;@Published&lt;/code&gt; property of the name. Therefore, let’s breakdown how the publisher is created in &lt;code&gt;ContentObject.markdownTitlePublisher(forURL:)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;markdownTitlePublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fromURL&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&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;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;dataTaskPublisher&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;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arg&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="kt"&gt;DataTaskPublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;  &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;data&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="nv"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;)&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;components&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;separatedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newlines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;InvalidTextError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;catch&lt;/span&gt;&lt;span class="p"&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;return&lt;/span&gt; &lt;span class="kt"&gt;Just&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="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&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;h4&gt;
  
  
  Functional Programming with Combine
&lt;/h4&gt;

&lt;p&gt;Luckily, Combine provides already built-in methods for publishers for the three main asynchronous APIs, which I talked about previously: NotificationCenter, Timer, and URL tasks. In this case, let’s look at how URL Task publisher transforms to useable String value for the name property:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;tryMap&lt;/code&gt; reads the first line of text by decoding the binary &lt;code&gt;data&lt;/code&gt; into text and reading the first line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;catch&lt;/code&gt; converts the useless error into nil...
&lt;strong&gt;For a SwiftUI View to use a publisher, the publisher must always handle the error in order to assign the value.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;compactMap&lt;/code&gt; removes any nil values from the publisher pipeline&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eraseToAnyPublisher&lt;/code&gt; uses type erasure to remove the specifics conversions taken place.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, with all the plumbing in place, SwiftUI and Combine will display the display the first line of the markdown file.&lt;/p&gt;

&lt;p&gt;In conclusion, Combine really shows it’s power when it comes to UI updates (not just SwiftUI but UIKit, AppKit, etc…) and any situation where reactive programming makes sense such as when there are multiple publishers and subscribers. However if you are comfortable with Promises and Futures and your code is more simple and straightforward it’s perfectly reasonable to go with that method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5AFEJJVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/vk284nkoavu-e1569349443454-300x300.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5AFEJJVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://learningswift.brightdigit.com/wp-content/uploads/sites/2/2019/09/vk284nkoavu-e1569349443454-300x300.jpg" alt="Virtual Reality"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Coroutines - The Future of Asynchronous Operations &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Before closing out, there has been proposals for making Promises and Futures native in Swift along with the syntactic sugar some common in other languages known as &lt;strong&gt;Coroutines&lt;/strong&gt;. (Read more about &lt;strong&gt;Coroutines&lt;/strong&gt; in &lt;a href="https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619"&gt;Chris Latner’s proposal&lt;/a&gt;.) Let’s take a look at our earlier example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;url&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://jaspervdj.be/lorem-markdownum/markdown.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;url&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;response&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="err"&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, a closure is based as a parameter along with a task. However a Promise or Future might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;url&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://jaspervdj.be/lorem-markdownum/markdown.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;promise&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="kt"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="kt"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&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;data&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;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;promise&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With syntactic sugar like &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt;, it become even cleaner with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;url&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://jaspervdj.be/lorem-markdownum/markdown.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&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;data&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;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To declare a method as being asynchronous and wrap a previous method (using a &lt;code&gt;callbackWrap&lt;/code&gt; method for now) such as &lt;code&gt;setupSite&lt;/code&gt; previously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;withTheme&lt;/span&gt; &lt;span class="nv"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;callbackWrap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;continuation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;withTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&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;continuation&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="p"&gt;}&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;continuation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site&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="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; along with &lt;code&gt;Combine&lt;/code&gt;, Swift can really take advantage of asynchronous programming both from the simple Promise/Future mindset as well as the Reactive programming paradigm.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the Right Toolset?
&lt;/h2&gt;

&lt;p&gt;In conclusion, developers have some key decisions when it comes to the best way to deal with asynchronous, parallelism, and concurrency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take Advantage of Your Hardware - make sure not to lock down the whole device or application with one thread but allow for many actions to take place simultaneously&lt;/li&gt;
&lt;li&gt;Avoid Convoluted Logic in favor of Easy Maintenance - make it easier for the &lt;em&gt;next&lt;/em&gt; developer to update your code, don’t over optimize without componentizing&lt;/li&gt;
&lt;li&gt;Provide Fast UI Experience over a Speedier Logic - giving healthy feedback to the user of what’s going on is more important than a faster application - again avoid freezing your app and device&lt;/li&gt;
&lt;li&gt;Use Abstractions As Much As Possible - unless you are into highly processor intense applications - use Apple’s provided abstractions (i.e. Combine, etc..) rather lower-level direct APIs (i.e. Threads)&lt;/li&gt;
&lt;li&gt;Avoid Callback Hell with Promises and Futures - for simple non-UI code use Promises and Futures to organize multiple asynchronous calls as opposed to a pyramid of callbacks&lt;/li&gt;
&lt;li&gt;For UIs on the latest Operating Systems (iOS 13, watchOS 6, tvOS 13, Catalina) use Combine - Combine gives the OS better control of the flow multiple asynchronous operations using reactive patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully this article gives you more guidance on how to better manage multiple operations and optimize your application for a better user experience. I am looking forward to even better APIs with Swift in the future.&lt;/p&gt;

&lt;p&gt;If you have any questions, reply to me on &lt;a href="https://twitter.com/leogdion"&gt;Twitter @leogdion&lt;/a&gt; and if you want to learn more fill out the form below:&lt;/p&gt;

</description>
      <category>swift</category>
      <category>combine</category>
      <category>gcd</category>
      <category>ios</category>
    </item>
    <item>
      <title>Best Backend for your iOS App</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Wed, 21 Aug 2019 12:00:07 +0000</pubDate>
      <link>https://dev.to/leogdion/best-backend-for-your-ios-app-53g9</link>
      <guid>https://dev.to/leogdion/best-backend-for-your-ios-app-53g9</guid>
      <description>&lt;p&gt;Choosing the best backend for your iOS App can be a challenge? The options are robust and depend on a number of questions like-do you need a cloud service? Should you run your own server? Should you use &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;Cloudkit&lt;/a&gt;, &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt;, or another option? We dig into these questions and the other things you should consider when looking into back-end and cloud services for your iOS app.&lt;/p&gt;

&lt;p&gt;First, it’s important to point out that cloud services aren’t needed in every case when it comes to an iOS (or any mobile) app. So, what can you do without them? A lot, actually.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So one thing to consider is — there’s a lot you can get away with without even doing cloud services. The thing with an iOS app is you can store your data in something like iCloud or in a lot of cases people really don’t need the cloud to store their data. They can just store it on their phone itself. &lt;a href="https://share.transistor.fm/s/ffcb9fc1"&gt;EmpowerApps.Show — Episode 8 — Cloud and Backend Services&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fa4Ubzzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2AI3ayW-_JURbTvDWSg0JmOg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fa4Ubzzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2AI3ayW-_JURbTvDWSg0JmOg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Backend is No Backend?
&lt;/h2&gt;

&lt;p&gt;Is the best backend for your iOS app, no backend? In many cases, you don’t need cloud services for storage as you can just use the phone itself. When you’re building an app, you should consider whether you really need something stored in the cloud or are you able to use a manual mechanism to back up the data? If you can create a mechanism that saves the data into cloud storage as a file, it could save you a lot of time and money.&lt;/p&gt;

&lt;p&gt;In cases where you are dealing with private or sensitive data, it’s a good idea to stick with your phone. This is especially true when dealing with third-party apps like &lt;a href="https://developer.twitter.com"&gt;Twitter&lt;/a&gt; or &lt;a href="https://developers.google.com/youtube/"&gt;YouTube&lt;/a&gt; or another API where you’re not really storing data but storing in the third party’s structure. You can use that API as your database.&lt;/p&gt;

&lt;p&gt;As an example, in an app built for doctors and nurses to receive continuing education for their career, all the data was essentially stored using &lt;a href="https://developer.apple.com/documentation/coredata"&gt;Core Data&lt;/a&gt; which is a &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite&lt;/a&gt; database abstraction layer. It was all stored locally because their time and budget didn’t allow for anything else. There was a manual backup process put in place that would run and create a zip file of the data and save it on the device. If they needed to restore it, they could sort it in the cloud and restore it back to their phones.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Cloud and Backend Services For Apps&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-cloud-and-backend-services-for-apps" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-cloud-and-backend-services-for-apps" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-cloud-and-backend-services-for-apps" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-cloud-and-backend-services-for-apps" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-cloud-and-backend-services-for-apps"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="Cloud and Backend Services For Apps" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dbOYNAiE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2Avy6KWuNftrYDMhqj9Qng-g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dbOYNAiE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2Avy6KWuNftrYDMhqj9Qng-g.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Cloud Services for Your Best Backend
&lt;/h2&gt;

&lt;p&gt;The best backend for your iOS app can be really helpful if you’re storing data or syncing across multiple devices. For example, note-taking apps that are available on all Apple devices (phones, iPads, computers) use a combination of &lt;a href="https://www.icloud.com"&gt;iCloud&lt;/a&gt; and &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;CloudKit&lt;/a&gt; to store information on the back-end. When a user opens their notes on their Mac or their iPhone, they are all available and accessible because they are stored in the cloud.&lt;/p&gt;

&lt;p&gt;If you’ve decided that you do need back-end storage-what are some things you should consider when choosing the right path? Let’s take a look.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One thing to consider is timeline and budget and specifically what is the purpose of this app? Is this just a simple MVP or is it more of a long-term app that needs to be well architected when I first starts off?&lt;a href="https://share.transistor.fm/s/ffcb9fc1"&gt;**EmpowerApps.Show — Episode 8 — Cloud and Backend Services&lt;/a&gt;**&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Purpose of Your App: MVP Vs. Enterprise
&lt;/h2&gt;

&lt;p&gt;Take a look at the app you’re designing. Is it an MVP or a more robust Enterprise app?&lt;/p&gt;

&lt;p&gt;An MVP (Most Viable Product) is a simple app that is just proving it’s something your customers will actually want. It’s something you need to get out quickly and is most likely a bare-bones version of the basic features you think your customers will want.&lt;/p&gt;

&lt;p&gt;Or, does the app need to be well-architected right from the beginning, like an Enterprise app for a Fortune 500 company? If you’re going this route, you’re going to want something that is more robust and customizable and it should be something you’ll want to work with for the long-term.&lt;/p&gt;

&lt;p&gt;If you’re looking to get out an MVP, the best backend for your iOS app is something that’s simple, easy, and cheap and will just get the job done. It should be something that can be easily tested by your audience so you can see if it works with the needs of your users.&lt;/p&gt;

&lt;p&gt;You’ll also want to make sure you have some healthy abstraction with your API communication when you are writing your Swift of Objective-C code to talk to the back-end. That way, you will be able to pivot easily if you decide to use a different service at a later date and your users won’t see anything different on the front end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported Devices
&lt;/h2&gt;

&lt;p&gt;Are you only supporting Apple devices? Are you also going to support the web? Are going to support Android? Are going to support Windows and Linux desktops? Are you going to support the internet of things? These are all questions to consider when deciding what back-end services to use.&lt;/p&gt;

&lt;p&gt;If you’re only supporting Apple devices, you may want to consider &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;CloudKit&lt;/a&gt;, an option we’ll discuss in more detail below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complex Vs. Simple Queries
&lt;/h2&gt;

&lt;p&gt;Some tasks, like relational data, are best performed through some sort of SQL database. However others might work better with a document storage type database. Most importantly, you should consider whether you need to aggregate your data or whether you need to create filters. In other words, do you need to view your data in a lot of different ways to combine your data set.&lt;/p&gt;

&lt;p&gt;Conversely many simple document-based cloud storage options are cheaper. Therefore, if you’re willing to offload a lot of the complexity of a good query over to the device like your iPhone document-based storage like &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt; might be a good option. Additionaly, you could consider caching your complex data for later rather than querying the data each time. Remember, a simple query would need to lookup data with a particular ID only.&lt;/p&gt;

&lt;p&gt;You need to ask yourself if you’re willing to offload a lot of the complexity of a good query over to the device like your iPhone, or is it more important to have that information on the server. The best backend for your iOS app might not be the easiest to query but the cheapest and easiest to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outside Communication
&lt;/h2&gt;

&lt;p&gt;Besides storage, you should also ask yourself if you will need any outside communication or outside scheduled jobs. This may occur if the user does something that creates data and then you need to be able to access that data even if they have their phone off such as email newsletter, shipping orders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Expertise of Your Team
&lt;/h2&gt;

&lt;p&gt;This is a big factor because if their expertise is.net, you’re probably better off using a Windows back end with an &lt;a href="https://www.microsoft.com/en-us/sql-server/default.aspx"&gt;SQL Server&lt;/a&gt; and C#. If you’re already getting a decent price on Azure, for instance, use it because that’s what your team is an expert in. If your team is well versed in Swift, you may want to consider &lt;a href="http://vapor.codes/"&gt;Vapor&lt;/a&gt; for your backend. Check out &lt;a href="https://brightdigit.com/blog/2019/03/19/vapor-swift-backend-review/"&gt;our review of Vapor here for more details.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  User Interface (UI)
&lt;/h2&gt;

&lt;p&gt;We also recommend doing some user-focused design to come up with the kind of data that your users will need. Afterwards, work your way back towards how you would need to store that. For instance,yYou can start by building out the UI of the app and essentially fake the data to make sure that data is what the customers want and then go back from there. Get your UI taken care of because that’s the thing the users are going to see.&lt;/p&gt;

&lt;p&gt;These factors, plus the budget you’re working with and the time you have to spend are all factors to consider when thinking about back-end storage.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Cloud and Backend Services For Apps&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-cloud-and-backend-services-for-apps" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-cloud-and-backend-services-for-apps" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-cloud-and-backend-services-for-apps" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-cloud-and-backend-services-for-apps" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-cloud-and-backend-services-for-apps"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="Cloud and Backend Services For Apps" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The Options
&lt;/h2&gt;

&lt;p&gt;Once you’ve asked yourself all the necessary questions, you’ll want to start looking at the options that fit your needs and budget. If you feel you need back-end support, you’ll need to decide the best option for your app and your user. Here are some options to consider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;…Some of the advantages of hosting your own is the fact that you can customize everything down to the minutiae, I mean you basically have a whole machine that you can work with that is also the disadvantage because the burden is on you to make sure everything is set up correctly wear as a lot of these other services. They pretty much can take care of everything. All you need to do is write your app code and get your database setup. &lt;a href="https://share.transistor.fm/s/ffcb9fc1"&gt;EmpowerApps.Show — Episode 8 — Cloud and Backend Services&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hosting a Server For Your Backend
&lt;/h2&gt;

&lt;p&gt;The most customizable and robust option is just to host your own server. You can buy your own server and host it at a site with a virtual machine like &lt;a href="https://aws.amazon.com/ec2/"&gt;AWS EC2&lt;/a&gt;, &lt;a href="https://www.linode.com/?r=97e09acbd5d304d87dadef749491d245e71c74e7"&gt;Linode&lt;/a&gt; or &lt;a href="https://m.do.co/c/255904441a32"&gt;DigitalOcean&lt;/a&gt;. &lt;a href="https://www.linode.com/?r=97e09acbd5d304d87dadef749491d245e71c74e7"&gt;Linode&lt;/a&gt; is an affordable option at $5/month. However, you may not want a complete server both due to the cost but also the need for maintenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; is owned by Google but is open source and even AWS, Linode and Digital Ocean also host Kubernetes instances. This is a popular option for good reason, especially in the dev-op space.&lt;/p&gt;

&lt;p&gt;If you’re starting from scratch and want something to play with, Heroku is a great option. Their free tier which includes a &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; database is plenty to start with.&lt;/p&gt;

&lt;p&gt;Speaking of PostgreSQL, you’ll need to set up your own database, as well as other server software. Here are some specific options to consider:&lt;/p&gt;

&lt;h3&gt;
  
  
  Databases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mysql.com/"&gt;MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/"&gt;MariaDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/en-us/sql-server/default.aspx"&gt;SQL Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll need something to server content whether it’s images, JSON, or HTML:&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Software
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.iis.net/"&gt;IIS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nginx.com/"&gt;Nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httpd.apache.org/"&gt;Apache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also consider some other services such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt; for monitoring, caching and CDN&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://newrelic.com/"&gt;New Relic&lt;/a&gt; for monitoring and security&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://supervisord.org/"&gt;Supervisor&lt;/a&gt; for services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re working with a simple MVP or releasing only for Apple, we would not recommend hosting your own. If you have simple needs go with the simplest solution and then plan on scaling out from there according to the growth of your own needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  CloudKit as Your Backend
&lt;/h2&gt;

&lt;p&gt;One really affordable option worth exploring in more detail is Apple’s back-end storage system, &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;CloudKit&lt;/a&gt;. &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;CloudKit&lt;/a&gt; is fairly simple to use if you’re sticking with iOS. It comes with push notifications and is completely native to Apple. If you’re running a Mac app or an iPad app or using an Apple Watch or Apple TV, it’s really easy to use. It also includes a JavaScript component for the web. It is an easy yes is if you’re just going to target Apple devices. When using &lt;a href="https://developer.apple.com/icloud/cloudkit/"&gt;CloudKit&lt;/a&gt;, you would be fine offloading some stuff onto the iPhone itself if the data isn’t too complex.&lt;/p&gt;

&lt;p&gt;If you absolutely need to run outside backups or outside cron jobs and can’t do it on an iPhone or an iPad, then you might want to consider another option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase as Your Backend
&lt;/h2&gt;

&lt;p&gt;Another popular option is &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt;. &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt; is the most popular mobile back-end as a service not only because of price but also because it’s available on a plethora of devices. But beware, on the surface, it seems really appealing but we would hesitate when recommending it for projects that might scale. If you want to learn how to do real-time database integration in a web browser and you don’t want to introduce apps where you have to create a lot of extra code in order to access data, &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt; is a great way to go about it.&lt;/p&gt;

&lt;p&gt;But, while it is popular, after some research it appears that not a lot of enterprise-grade companies are relying on it. We recommend using it for very very simple situations where you have data that is not going to change in structure over time, data that’s generally flat, and when you don’t have to do lots of complex queries. Really study the limitations before you jump into it as it may not be a good fit for what you are looking for.&lt;/p&gt;


&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;Cloud and Backend Services For Apps&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/empowerappsshow"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        EmpowerApps.Show  

      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-cloud-and-backend-services-for-apps" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-cloud-and-backend-services-for-apps" src="/assets/playbutt.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-cloud-and-backend-services-for-apps" src="/assets/pausebutt.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-cloud-and-backend-services-for-apps" alt="EmpowerApps.Show" src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4HcUF9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--tU-HGV38--/c_fill%2Cf_auto%2Cfl_progressive%2Cq_auto/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
  &lt;/div&gt;
  &lt;div class="hidden-audio" id="hidden-audio-cloud-and-backend-services-for-apps"&gt;
    
      
      Your browser does not support the audio element.
    
    &lt;div id="progressBar" class="audio-player-display"&gt;
      &lt;a href="/empowerappsshow/cloud-and-backend-services-for-apps"&gt;
        &lt;img width="420" height="420" id="episode-profile-image" alt="Cloud and Backend Services For Apps" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbuqGl43--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--5uj3nX_6--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_420%2Cq_auto%2Cw_420/https://dev-to-uploads.s3.amazonaws.com/uploads/podcast/image/79/bc91645a-2ecb-418e-b1e6-44f1328ceab9.jpg"&gt;
        &lt;img id="animated-bars" src="/assets/animated-bars.gif" alt="animated volume bars"&gt;
      &lt;/a&gt;
      &lt;span id="barPlayPause"&gt;
        &lt;img class="butt play-butt" src="/assets/playbutt.png" alt="play"&gt;
        &lt;img class="butt pause-butt" src="/assets/pausebutt.png" alt="pause"&gt;
      &lt;/span&gt;
      &lt;span id="volume"&gt;
        &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
          &lt;span id="volbutt"&gt;
            &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnhE4kcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume.png"&gt;
          &lt;/span&gt;
          &lt;span class="range-wrapper"&gt;
            
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
          &lt;img alt="mute" class="icon-img" height="16" width="16" src="https://res.cloudinary.com/practicaldev/image/fetch/s--prPRZNLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/volume-mute.png"&gt;
        &lt;/span&gt;
        &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
      &lt;/span&gt;
      &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
        &lt;span id="buffer"&gt;&lt;/span&gt;
        &lt;span id="progress"&gt;&lt;/span&gt;
        &lt;span id="time"&gt;initializing...&lt;/span&gt;
        &lt;span id="closebutt"&gt;×&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Final Tips
&lt;/h2&gt;

&lt;p&gt;We know we’re leaving you with a lot of information, so as a final tip, we wanted to add this piece of advice-when considering any storage solutions, check to see if there are any big companies using it. The best backend for your iOS app needs to be something that’s rock solid and stable and gets a lot of support, just check out what the big guys are doing. You can be sure that the companies with a lot of money to spend will have taken the time to research and vet these solutions so you can consider anything they are using, a little bit safer than an under-researched option.&lt;/p&gt;

&lt;p&gt;Typically they’ll go with one of the big three: AWS, Azure, IBM. Or, they’ll decide to host their own.&lt;/p&gt;

&lt;p&gt;Whatever you choose, remember, if you need to pivot, do it early. Don’t do it when it’s too late. If you feel like your data isn’t a good fit for whatever you end up, make the change as quickly as you can because you’re not going to want to be burnt out by constantly trying to get your data to fit in particular space.&lt;/p&gt;

&lt;p&gt;Want even MORE info? Check out the &lt;a href="https://share.transistor.fm/e/ffcb9fc1"&gt;entire conversation here&lt;/a&gt; and&lt;a href="https://brightdigit.com/subscribe/"&gt; subscribe to our newsletter to stay informed.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://brightdigit.com/blog/2019/07/30/best-backend-for-your-ios-app/"&gt;https://brightdigit.com&lt;/a&gt; on July 30, 2019.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>server</category>
      <category>cloud</category>
      <category>backend</category>
    </item>
    <item>
      <title>Podcasting — Getting Started — Whys and Hows</title>
      <dc:creator>leogdion</dc:creator>
      <pubDate>Tue, 25 Jun 2019 12:36:56 +0000</pubDate>
      <link>https://dev.to/leogdion/podcasting-getting-started-whys-and-hows-5dcm</link>
      <guid>https://dev.to/leogdion/podcasting-getting-started-whys-and-hows-5dcm</guid>
      <description>&lt;p&gt;It has been at least 15 years but I remember as soon as iTunes came to Windows, I downloaded podcasts. For example, it could have been the software development podcast, &lt;a href="https://dotnetrocks.com/" rel="noopener noreferrer"&gt;dotNet Rocks&lt;/a&gt;, or the financial podcast, &lt;a href="https://www.npr.org/sections/money/" rel="noopener noreferrer"&gt;Planet Money&lt;/a&gt;, giving a narration and analysis of the 2008 Financial Crash as it happened. &lt;strong&gt;Generally speaking, podcasting as these podcasts do, gives specific audiences an in-depth specialized analysis without the need to appeal to the general audience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Therefore in 2017, I decided to jump into podcasting and start two podcasts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F1%2Ao2Ff7jaeH-KQDGKQQaPZyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F1%2Ao2Ff7jaeH-KQDGKQQaPZyg.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;span&gt;OKProductive — my podcast with Erik on personal productivity&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F1%2AIP5uZcc6sz3foTG02_PwXQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F1%2AIP5uZcc6sz3foTG02_PwXQ.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;span&gt;My Podcast about Apple, Business, Apps, and Development&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://okproductive.com/" rel="noopener noreferrer"&gt;one on personal productivity&lt;/a&gt; and &lt;a href="https://www.empowerapps.show/" rel="noopener noreferrer"&gt;another for my business on software development for Apple hardware&lt;/a&gt;. Important to realize, both podcasts are some sort of combination of passion, business, and expertise. And so, I want to talk about the ins and outs of podcasting.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why should you start a podcast&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How to build content&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How to stay organized&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recording and editing audio&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hosting and Publishing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reaching Your Audience&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ojL0JPZrAGE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Recent Talk I did at Lansing Marketing Hackers on Podcasting&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;First of all, the #1 question you should ask is &lt;strong&gt;why you should start a podcast&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fmelanie-dretvic-699931-unsplash-469-1.jpg%3Fresize%3D640%252C593%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fmelanie-dretvic-699931-unsplash-469-1.jpg%3Fresize%3D640%252C593%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Should You Start a Podcast?
&lt;/h3&gt;

&lt;p&gt;Podcasting may sound simple at first but to really be successful at it you need perseverance. Therefore, you need to really have a good reason and passion to do for a while. For this reason, rather than discussing &lt;strong&gt;how to start podcast&lt;/strong&gt; let’s discuss the why.&lt;/p&gt;

&lt;p&gt;Most importantly, sharing your expertise on the web provides a great example to others. However, more so than a written format, talking about a topic is a more natural means for people. Uniquely, rather than giving a talk to 40 people, podcasting allows you to present on topic many times over. In addition, not only can you sell yourself but a product as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sell A Product
&lt;/h3&gt;

&lt;p&gt;Podcasting can be a great way to sell your products. By starting a podcast, you can give your products a narrative and showcase as to how they are helpful. However, &lt;strong&gt;the most important part of selling anything on the web is to provide actual informative valuable content.&lt;/strong&gt; Don’t just sell but provide advice — You build trust as well as true expertise on the product’s subject matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enjoy a Topic or Hobby through Podcasting
&lt;/h3&gt;

&lt;p&gt;While selling yourself or your products are good reasons, you need to have some sense of enjoyment or passion to really carry out the momentum of producing a podcast show. Recently on Pat Flynn’s Smart Passive Income podcast,&lt;a href="https://www.smartpassiveincome.com/podcasts/how-powerhouse-youtuber-marques-brownlee-mkbhd-grew-his-massive-brand/" rel="noopener noreferrer"&gt; he interviewed MKBHD&lt;/a&gt;, a YouTube tech reviewer with over 8 million subscribers. &lt;strong&gt;MKBHD revealed on the show he produced 100 videos before he even had 100 subscribers.&lt;/strong&gt; Building an audience with your show is going to be a long and slow process. For this reason, having enjoyment and passion in podcasting will give you the momentum to carry it through that long process. As a result, if you do decide to start a show though, it’s important to know where to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  How To Get Started Podcasting?
&lt;/h3&gt;

&lt;p&gt;Podcasting involves five components: &lt;strong&gt;content, organization, audio, hosting, and reaching your audience&lt;/strong&gt;. With this in mind, having engaging content is perhaps the most important.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fpatrick-tomasso-71909-unsplash-690-e1560427956814-1024x576.jpeg%3Fzoom%3D2%26resize%3D640%252C360%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fpatrick-tomasso-71909-unsplash-690-e1560427956814-1024x576.jpeg%3Fzoom%3D2%26resize%3D640%252C360%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Content
&lt;/h3&gt;

&lt;p&gt;Based on why you starting your podcast and the type of show you are doing, you need to build a list of topics for your show. With this intention, you need build on your existing expertise and passion while also finding your audience and seeking their pain points.&lt;/p&gt;

&lt;h4&gt;
  
  
  Build On Your Existing Expertise and Passion
&lt;/h4&gt;

&lt;p&gt;As a result, by building on your passion and expertise, you sound natural and engaging. Nevertheless, if you get stuck compiling a list of topics based on your expertise alone, you can look to your potential audience online. Additionally your audience online will give you insight into their questions or challenges.&lt;/p&gt;

&lt;h4&gt;
  
  
  Find Your Audience and Their Challenges
&lt;/h4&gt;

&lt;p&gt;The web is a great way to reach your audience but it’s also a great way for you to find your audience and the challenges they face. For example, Reddit, Quora, Stackoverflow, Slack Workspace, Youtube Comments, Twitter, Facebook Groups, and any website forum — as long as there is engagement there — is a great opportunity to see what your audience is facing as far as difficulties and where their pain is. They don’t need to be listeners of your podcast already — they just need to be the people you are targeting. Along with your knowledge, you should have enough content to get started. The important thing is to keep that content organized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fsamuel-zeller-360588-unsplash-703-e1560428140697-1024x514.jpeg%3Fzoom%3D2%26resize%3D640%252C321%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fsamuel-zeller-360588-unsplash-703-e1560428140697-1024x514.jpeg%3Fzoom%3D2%26resize%3D640%252C321%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Staying Organized
&lt;/h3&gt;

&lt;p&gt;There are two key components to staying organized with your podcast: having prepared notes before you record and having a consistent recording and publishing schedule.&lt;/p&gt;

&lt;h4&gt;
  
  
  Have Prepared Notes Before You Record
&lt;/h4&gt;

&lt;p&gt;Behind the scenes of every great show are some sort of notes when it comes to the topic of each episode. Moreover, even when talking off-the-cuff, it’s important to have anchor points for your discussion. Furthermore, some shows even go so far so to have a complete script. In the end, it really depends on you and the type of show you are producing. Most importantly, the worst flaw is losing your train of thought and having &lt;strong&gt;not enough to talk about.&lt;/strong&gt; Therefore, the most natural way of doing this is by talking about what you are an expert at and passionate about. As a result, there are several methods of breaking down any topic into prepared notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 W’s — Who, What, Where, Why, HoW&lt;/li&gt;
&lt;li&gt;Chronological Narrative&lt;/li&gt;
&lt;li&gt;Essay Format — Thesis Statement with Three Points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this in mind, whatever format you choose make sure you have a structure and stick with it. If your content has structure, it will give your audience an easier way to organize the content and make it memorable. In addition, building these pre-show notes are a great way to indicate to yourself that you have enough content. Afterwards, these pre-show notes give you an skeleton you will fill in later for the show notes which will be posted publicly with your episode’s metadata. For example, check out &lt;a href="https://docs.google.com/document/d/e/2PACX-1vQlL4J06mtBQDlc5JJuWxd1k7gLshk4wsyy-CPqFypSJ_I29UUZnqwmTADXh448_YsfcqYgGYLDsWOy/pub" rel="noopener noreferrer"&gt;this sample from the episodes Erik and I did for OK Productive on the book Atomic Habits by James Clear&lt;/a&gt;. In the same way pre-show notes give you a skeleton to work with, consistency in your schedule can help continue your show’s momentum.&lt;/p&gt;

&lt;h4&gt;
  
  
  Have A Consistent Schedule
&lt;/h4&gt;

&lt;p&gt;Having a consistent schedule, both in recording and publishing, sets your audience expectations and makes sure you build a habit and flow with recording. For example, what I do set aside every Thursday morning to record an episode of each of my podcasts and publish every other week each podcast. By doing this, I have built a habit and expectation on my part that I’ll record every week. Additionally, with the recording to publishing ratio being 2:1, I have now a buffer of episodes, in case something happens: sickness, vacation, etc…. As far as publishing, I have a pretty consistent schedule, publishing every Saturday night or early Sunday morning. Based on playing around with different days, it seems most folks download episodes at the beginning of the work week. This could differ with your audience but clearly setting those expectations are helpful to your audience. Now that we have pre-episode notes and a regular recording schedule, let’s talk about recording.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fneil-godding-179009-unsplash-687-e1560428361178-1024x512.jpeg%3Fzoom%3D2%26resize%3D640%252C320%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi2.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fneil-godding-179009-unsplash-687-e1560428361178-1024x512.jpeg%3Fzoom%3D2%26resize%3D640%252C320%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Audio
&lt;/h3&gt;

&lt;p&gt;The most technical aspect of podcasting is recording and editing your episode. However before we began, I want to reiterate one point: &lt;strong&gt;don’t sink money in the best equipment until you are sure that you’ll stick with podcasting&lt;/strong&gt;. Surprisingly, you may already have much of the equipment and there is plenty of free software to do this. As a result, I’d recommend spending some money on better equipment and software perhaps around the 6 month — 9 month time range or once you’ve recorded approximately 10–12 episodes and have a rhythm in your schedule. Firstly, the equipment which takes in your voice before anything else is going to be your microphone.&lt;/p&gt;

&lt;h4&gt;
  
  
  Your Podcasting Microphone
&lt;/h4&gt;

&lt;p&gt;Your microphone is going to be your first connection to your audience. When first starting off, I’d recommend using a microphone — any microphone. Most importantly, don’t rely on your laptop microphone and webcam microphone for your audio. In addition, test your audio recording before moving to an editing phase. As far as microphone upgrades, the next step is spending money ($50 — $99) on something like what I use: &lt;a href="https://www.amazon.com/dp/B004QJOZS4/ref=cm_sw_em_r_mt_dp_U_mPKRCbM5KJ91F" rel="noopener noreferrer"&gt;Audio-Technica ATR2100-USB&lt;/a&gt; In addition, they also sell a &lt;a href="https://www.amazon.com/gp/product/B01MSQFIRE/ref=ppx_od_dt_b_asin_title_s00?ie=UTF8&amp;amp;psc=1" rel="noopener noreferrer"&gt;combo which include a pop filter and studio&lt;/a&gt;, that I use and highly recommend.&lt;/p&gt;

&lt;p&gt;Once you’ve reached a point where you wish to go even more professional, you’ll want to look a more expensive microphones and a mixer/pre-amp. These will give an even better sound, more control, and better realtime feedback of your audio. Here are some links which you might find helpful:  Therefore, once you have a good microphone for recording, you’ll need software to record your audio.&lt;/p&gt;

&lt;h4&gt;
  
  
  Recording and Editing Your Audio
&lt;/h4&gt;

&lt;p&gt;Recording software can be fairly simple and inexpensive. For example, there’s free software such as &lt;a href="https://www.apple.com/mac/garageband/" rel="noopener noreferrer"&gt;Garageband&lt;/a&gt; and &lt;a href="https://www.audacityteam.org/" rel="noopener noreferrer"&gt;Audacity&lt;/a&gt; for macOS and Windows/Linux respectively. However, if you are planning to edit your podcast then it maybe worth your money to purchase something like: &lt;a href="https://www.apple.com/logic-pro/" rel="noopener noreferrer"&gt;Apple’s Logic Pro&lt;/a&gt; or &lt;a href="https://www.adobe.com/products/audition.html" rel="noopener noreferrer"&gt;Adobe Audition&lt;/a&gt; which give you more granular control over editing functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote Interviews&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Specifically, remote interviews can present its fair share of challenges. For example there are recording apps such as &lt;a href="https://zencastr.com/" rel="noopener noreferrer"&gt;Zencaster&lt;/a&gt; which specialize in this. Additionally, you could also record your interview over a conferencing service like &lt;a href="https://zoom.us/" rel="noopener noreferrer"&gt;Zoom&lt;/a&gt; or &lt;a href="https://hangouts.google.com/" rel="noopener noreferrer"&gt;Google Hangouts&lt;/a&gt; strip the audio portion and turn that into an episode. Surprisingly though, the conferencing choice of most podcasters is &lt;a href="https://www.skype.com/" rel="noopener noreferrer"&gt;Skype&lt;/a&gt;. However you’ll want to record you and your interviewee on separate tracks. For instance as a macOS user, I use Soundflower to map my audio channels properly (i.e. my microphone and Skype audio to separate tracks). Furthermore, I also encourage my guest to record there own audio since sound quality via Skype isn’t the best.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editing Audio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Therefore, once you’ve recorded your audio, the next step is editing. Most importantly, having a great recording helps increase the quality of the recording overall. That is to say avoiding filler words, dead air, and meandering rants will improve the quality over any recording. However, in the end, editing will typically be needed. In the end, with editing, you want to make sure your sound is clear (and there are a variety of filters to do this) and is worth the effort. It can also be the most time consuming which is why I’ve started &lt;a href="https://www.podcastedition.com/" rel="noopener noreferrer"&gt;outsourcing my editing&lt;/a&gt;. As a result, we have a decent audio waveform for our episode, we’ll need to export the file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fmick-haupt-1321397-unsplash-692-e1560428540787-1024x512.jpeg%3Fzoom%3D2%26resize%3D640%252C320%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2Fmick-haupt-1321397-unsplash-692-e1560428540787-1024x512.jpeg%3Fzoom%3D2%26resize%3D640%252C320%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Exporting and Tagging Your Files
&lt;/h4&gt;

&lt;p&gt;An often forgotten step is including helpful metadata and proper formatting of the resulting mp3 file. Therefore, include the correct podcasting metadata and be sure to export as a mono 64kpbs mp3 file. Luckily, most editing tools provide a means to attach metadata such as podcast title, episode title, summary, and chapters with your episode. In the end, you’ll have your brand new episode as an mp3 file. The question then becomes where to upload your file. &lt;/p&gt;

&lt;h3&gt;
  
  
  Podcasting Hosts and Publishing
&lt;/h3&gt;

&lt;p&gt;Hosting your show can tend to be a bit of a maze:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a place to put your mp3 file&lt;/li&gt;
&lt;li&gt;a place to host your show’s website&lt;/li&gt;
&lt;li&gt;a way to broadcast to various MP3 players&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Hosting Your Mp3 Files
&lt;/h4&gt;

&lt;p&gt;First thing first, do not try to host your own mp3 files. In contract to simple web pages, these can take several MBs of data and when as many as a hundred people are downloading your episodes you can be bitten by download limits, speed issues, and various other issues. For example, when I first started out, I hosted the website on WordPress and the mp3 files on Amazon S3. In reality, this involved a lot of manual processes with each episode. Therefore, once my WordPress sites were hacked, I knew I had transition to a dedicated podcast hosting provider. As a result, I moved to &lt;a href="https://transistor.fm/?via=leo" rel="noopener noreferrer"&gt;Transistor&lt;/a&gt;, which has worked out fantastically. Other services which do this are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://soundcloud.com/" rel="noopener noreferrer"&gt;Soundcloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.blubrry.com/" rel="noopener noreferrer"&gt;Blubrry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.podbean.com/" rel="noopener noreferrer"&gt;Podbean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libsyn.com/" rel="noopener noreferrer"&gt;Libsyn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anchor.fm/" rel="noopener noreferrer"&gt;Anchor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Significantly, remember with all these hosts, there could be download caps, ad insertion, speed throttling and more which could hinderacne your experience. In the end you’ll get what you pay for. &lt;/p&gt;

&lt;p&gt;Be that as it may, each host will provide a place to upload your mp3 files, provide additional metadata, as well as more elaborate public show notes (as opposed to the pre-show notes you use for talking points). In the end you should have a publicly available RSS feed for your show. &lt;/p&gt;

&lt;h4&gt;
  
  
  Publishing to the Web
&lt;/h4&gt;

&lt;p&gt;As far a website, services like &lt;a href="https://transistor.fm/?via=leo" rel="noopener noreferrer"&gt;Transistor&lt;/a&gt;, come with a website of some sort and other services like Blubrry integrate with WordPress. However what’s even more important than a website is making sure your audio is delivered to the numerous podcast clients. Therefore, each podcasting host will deliver an RSS feed which contains metadata about the show as well as continually updated list of episodes. As as result, you’ll use this to &lt;em&gt;claim ownership of your podcast&lt;/em&gt;. Consequently, before submitting, make sure you have &lt;strong&gt;at the very least 3 episodes uploaded as well as a correct author email address setup with your podcast host&lt;/strong&gt;. With this in mind, while most clients let you manually add RSS feeds, most users will expect to find your show by searching. Therefore, here is a brief list of clients and how to get your show posted there:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iTunes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sign up through &lt;a href="https://itunesconnect.apple.com/login?module=PodcastsConnect" rel="noopener noreferrer"&gt;podcast connect&lt;/a&gt; with your show’s RSS feed. This is also used by Overcast and Castro as well. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Play Music&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sign up at &lt;a href="https://play.google.com/music/podcasts/" rel="noopener noreferrer"&gt;Google Play Music&lt;/a&gt; with your show’s RSS feed and validate with your author email address.&lt;br&gt;
&lt;strong&gt;Google Podcasts&lt;/strong&gt;&lt;br&gt;
As long as your website is easily searchable, Google should add it automatically. Use &lt;a href="https://www.google.com/webmasters/#?modal_active=none" rel="noopener noreferrer"&gt;Google WebmasterTools&lt;/a&gt; to verify this and be patient as it can take several days.&lt;br&gt;
&lt;strong&gt;Spotify&lt;/strong&gt;&lt;br&gt;
Go to &lt;a href="https://podcasters.spotify.com/" rel="noopener noreferrer"&gt;Spotify for Podcasters&lt;/a&gt; and submit yourRSS feed and validate. Some podcast host services offer this automatically such as&lt;br&gt;
&lt;a href="https://transistor.fm/?via=leo" rel="noopener noreferrer"&gt;Transistor.FM&lt;/a&gt;&lt;a href="https://podcasters.spotify.com/" rel="noopener noreferrer"&gt;.&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Stitcher&lt;/strong&gt;&lt;br&gt;
Submit your RSS feed through &lt;a href="https://partners.stitcher.com/PartnerAddFeed.php" rel="noopener noreferrer"&gt;the partner portal&lt;/a&gt; and validate your email address.&lt;br&gt;
&lt;strong&gt;Breaker&lt;/strong&gt;&lt;br&gt;
Submit your RSS feed through &lt;a href="https://www.breaker.audio/i/upstream" rel="noopener noreferrer"&gt;BreakerUpstream&lt;/a&gt; and verify your email address.&lt;br&gt;
&lt;strong&gt;Pocket Casts&lt;/strong&gt;&lt;br&gt;
Submit your &lt;a href="https://pocketcasts.com/submit" rel="noopener noreferrer"&gt;RSS feed to Pocket Casts&lt;/a&gt; and validate your email address.&lt;br&gt;
&lt;strong&gt;CastBox.fm&lt;/strong&gt;&lt;br&gt;
Apply through &lt;a href="https://castbox.fm/login?jump_uri=%2Fcreator%2Fchannels&amp;amp;country=us" rel="noopener noreferrer"&gt;creatorstudio&lt;/a&gt; and confirm with email address.&lt;br&gt;
&lt;strong&gt;Radio Public&lt;/strong&gt;&lt;br&gt;
Submit your RSS feed for &lt;a href="https://podcasters.radiopublic.com/signup" rel="noopener noreferrer"&gt;Radio Publichere&lt;/a&gt; and validate your emailaddress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tune In&lt;/strong&gt;&lt;br&gt;
Submit your RSS feed and other info to &lt;a href="https://help.tunein.com/contact/add-podcast-S19TR3Sdf" rel="noopener noreferrer"&gt;Tune Inhere&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Most importantly, for many of these services, it could take days for submissionto work. Surprisingly, some clients like iTunes Connect, actually mirror, ordownload and re-host your podcast on their platform. Additionally, if you areinterested in reaching Alexa, check out &lt;a href="https://www.youtube.com/watch?v=QrgWN6zEQtA&amp;amp;t=1s" rel="noopener noreferrer"&gt;this talk I hosted recently where PaulSchmidt talks about turning podcast episodes into Alexaskills&lt;/a&gt;. As a result, now that we have our podcast available on a variety of platforms the next step is reaching your audience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reaching Your Podcast Audience
&lt;/h3&gt;

&lt;p&gt;Congrats on getting your show recorded, edited, and hosted. However the realchallenge in podcasting comes from growing your audience. In that case, part of that is SEO tricks which can take advantage of Google and various podcast clients. Rather, you can go back to how you found your audience earlier and answer those questions with summaries and subscribable links to your episodes. By this means, you can realiably reach your audience directly.&lt;br&gt;
Social media has its advantages and disadvantages. However, if you don’t have anexisting audience, it can lead to not much return on your time. Nevertheless if you do post to social media, make sure it’s a platform your audience uses. Forinstance, converting 30 second clips into videos are a great way to capture youraudiences attention. Such as, &lt;a href="https://gist.github.com/leogdion/2e5f9b8311d6ecdc8c8202eadba0861d" rel="noopener noreferrer"&gt;this script I have written to convert 30 second mp3 files into videos for social media&lt;/a&gt;.Additionally, Erik, my OK Productive co-host and I use tools like&lt;a href="https://buffer.com/" rel="noopener noreferrer"&gt;Buffer&lt;/a&gt; to automate the process. Surprisingly, the other way to reach your audience is by an email newsletter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Emailing Your Audience
&lt;/h4&gt;

&lt;p&gt;Email may seem antiquated but &lt;a href="https://www.nytimes.com/2019/03/19/technology/new-social-network-email-newsletter.html" rel="noopener noreferrer"&gt;newsletters are more guaranteed to reach your audience then any social media channel.&lt;/a&gt; Accordingly, with email addresses, you can also directly reach your audience and get their feedback. As a result, once you have enough of a large audience, you begin to focus other written content as well and gauge interest accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leogdion.name/wp-content/uploads/2019/06/Podcasting-Process.pdf" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi0.wp.com%2Fleogdion.name%2Fwp-content%2Fuploads%2F2019%2F06%2FPodcasting-Process.png%3Fw%3D1300%26ssl%3D1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Whys and Hows of Podcasting
&lt;/h3&gt;

&lt;p&gt;Now you have a roadmap for discerning and getting started podcasting — from idea to publishing. Firstly, before jumping in, make sure the audience is there as well as your passion and expertise on the topic. Most importantly, have basic recording equipment and test recording an episode before posting. At the same time, begin having talking points and a schedule for recording. Consequently, find a good hosting provider for your mp3 and make sure to export in the correct format. As soon as, you have at least 3 episodes posted to your host, publish your RSS feed to various services. As a result, share your episodes on social media, in various audience websites and forums, and perhaps start an email newsletter to keep your subscribers in touch. to sum up, while podcasting is work, it can be lots of fun. Most importantly, you can always put in as much work as wish. If you have any questions, please be sure to reach out to me. I’d love to hear your podcasting stories and lessons you’ve learned.&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>marketing</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
