<?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>Forem: Amarildo Lucas</title>
    <description>The latest articles on Forem by Amarildo Lucas (@amarildo).</description>
    <link>https://forem.com/amarildo</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%2F40107%2Fc8732aff-930b-4dba-ad21-3f7399d251f9.PNG</url>
      <title>Forem: Amarildo Lucas</title>
      <link>https://forem.com/amarildo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/amarildo"/>
    <language>en</language>
    <item>
      <title>All SwiftUI Scene Types Noted</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Wed, 22 Mar 2023 16:21:12 +0000</pubDate>
      <link>https://forem.com/amarildo/all-swiftui-scene-types-noted-3bm8</link>
      <guid>https://forem.com/amarildo/all-swiftui-scene-types-noted-3bm8</guid>
      <description>&lt;h3&gt;
  
  
  Discover the latest SwiftUI scenes to help you present windows within your apps.
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;SwiftUI scenes&lt;/em&gt; are the main building blocks to structure and easily build more kinds of apps for apple platforms.&lt;/p&gt;

&lt;p&gt;While most developers build apps for iOS, knowing the different scene types helps you to &lt;strong&gt;easily build multiplatform apps&lt;/strong&gt; and follow the apple human interface guidelines to better design and architect your ideas.&lt;/p&gt;

&lt;p&gt;Below I share all the &lt;em&gt;SwiftUI scene&lt;/em&gt; types available with a resume of these key points concepts and their use.&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.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1679500612878%2Ffea52ce0-1632-49bc-a70b-ed13454a50a4.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.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1679500612878%2Ffea52ce0-1632-49bc-a70b-ed13454a50a4.png" alt="Sketch note All SwiftUI Scene Types Noted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Things to take in mind:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WindowGroup&lt;/code&gt;: Provides a way to &lt;strong&gt;build data-driven applications&lt;/strong&gt; across all of apple's platforms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DocumentGroup&lt;/code&gt;: Enables support for opening, creating, and saving documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Settings&lt;/code&gt;: Presents an interface for viewing and modifying an app's settings. (&lt;em&gt;macOS&lt;/em&gt; only)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Window&lt;/code&gt;: Present its content in a &lt;strong&gt;single, unique window&lt;/strong&gt;. (macOS - only.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;MenuBarExtra&lt;/code&gt;: Create a utility app that only shows in the menu bar.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope this sketch note is helpful to you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://amarildocodes.gumroad.com/l/all-swiftui-scene-types-noted" rel="noopener noreferrer"&gt;If you find this content helpful, please consider buying me a coffee by downloading the rich and high-resolution version of this sketch note here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;WWDC 2022&lt;/strong&gt;: &lt;a href="https://developer.apple.com/videos/play/wwdc2022/10061/" rel="noopener noreferrer"&gt;https://developer.apple.com/videos/play/wwdc2022/10061/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>swift</category>
      <category>swiftui</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Sketch Note: SwiftUI App Structure</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Mon, 20 Mar 2023 18:31:27 +0000</pubDate>
      <link>https://forem.com/amarildo/sketch-note-swiftui-app-structure-1ia9</link>
      <guid>https://forem.com/amarildo/sketch-note-swiftui-app-structure-1ia9</guid>
      <description>&lt;p&gt;The SwiftUI &lt;code&gt;App&lt;/code&gt; &lt;em&gt;protocol&lt;/em&gt; looks simpler but is decisive for your &lt;a href="https://developer.apple.com/documentation/swiftui/app-organization"&gt;applications' structure and organization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This sketch note shares a general look at the parts involved while implementing your app's entry point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pXn2BiaF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/noiv606i3rmto2q6eefl.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pXn2BiaF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/noiv606i3rmto2q6eefl.JPG" alt="Sketch Note: SwiftUI App Structure" width="880" height="1245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things to take in mind:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; The &lt;code&gt;App&lt;/code&gt; &lt;em&gt;protocol&lt;/em&gt; represents &lt;strong&gt;structure&lt;/strong&gt; and &lt;strong&gt;behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; The &lt;code&gt;body&lt;/code&gt; is the &lt;strong&gt;content&lt;/strong&gt; and can &lt;strong&gt;define scenes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;code&gt;Scene&lt;/code&gt; acts as the &lt;strong&gt;root view&lt;/strong&gt; of the view hierarchy and can be more than one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; The &lt;code&gt;@main&lt;/code&gt; initialize and call the &lt;code&gt;main()&lt;/code&gt; method which &lt;strong&gt;runs your app&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; The &lt;code&gt;init()&lt;/code&gt; &lt;strong&gt;runs by default&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; You can have &lt;strong&gt;multiple scenes&lt;/strong&gt; whose &lt;strong&gt;lifecycles will be managed by the system&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;I hope this sketch note is helpful to you.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftui</category>
      <category>ios</category>
      <category>sketchnotes</category>
    </item>
    <item>
      <title>CustomPresentationDetent Protocol Implementation in SwiftUI for Modal Presentations</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Wed, 08 Mar 2023 21:47:29 +0000</pubDate>
      <link>https://forem.com/amarildo/custompresentationdetent-protocol-implementation-in-swiftui-for-modal-presentations-o63</link>
      <guid>https://forem.com/amarildo/custompresentationdetent-protocol-implementation-in-swiftui-for-modal-presentations-o63</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;You can also read this article directly in my personal blog &lt;a href="https://amarildo.codes"&gt;https://amarildo.codes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can &lt;strong&gt;build more flexible and customized&lt;/strong&gt; &lt;strong&gt;modal view presentations&lt;/strong&gt; thanks to the &lt;code&gt;CustomPresentationDetent&lt;/code&gt; &lt;em&gt;protocol&lt;/em&gt;. It's common to use the &lt;code&gt;.sheet&lt;/code&gt; modifier when presenting a &lt;strong&gt;modal view&lt;/strong&gt;. However, occasionally we may need &lt;strong&gt;more control over the presentation&lt;/strong&gt; and the &lt;code&gt;.sheet&lt;/code&gt;'s default behavior will not be enough. &lt;strong&gt;This is where&lt;/strong&gt; &lt;code&gt;CustomPresentationDetent&lt;/code&gt; implementation begins because it enables us to change the presentation's behavior in the modal view.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will learn
&lt;/h2&gt;

&lt;p&gt;The article provides and outlines a step-by-step guide on how to use &lt;code&gt;CustomPresentationDetent&lt;/code&gt;. You will &lt;a href="https://github.com/amarildolucas/CustomPresentationDetent/tree/start-project"&gt;download a starter project&lt;/a&gt; that explains how to create an extension of &lt;code&gt;PresentationDetent&lt;/code&gt; &lt;em&gt;struct&lt;/em&gt; and implements &lt;code&gt;CustomPresentationDetent&lt;/code&gt; &lt;em&gt;protocol&lt;/em&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Getting started with the &lt;a href="https://github.com/amarildolucas/CustomPresentationDetent/tree/start-project"&gt;starter project&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create &lt;code&gt;PresentationDetent&lt;/code&gt; extension&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing &lt;code&gt;CustomPresentationDetent&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting started with the starter project
&lt;/h2&gt;

&lt;p&gt;Before we start, &lt;em&gt;clone/fork&lt;/em&gt; or &lt;a href="https://github.com/amarildolucas/CustomPresentationDetent/tree/start-project"&gt;download&lt;/a&gt; the project from the &lt;code&gt;main branch&lt;/code&gt; and run the following &lt;code&gt;git&lt;/code&gt; commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:amarildolucas/CustomPresentationDetent.git
&lt;span class="nb"&gt;cd &lt;/span&gt;CustomPresentationDetent
git checkout start-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; &lt;em&gt;branch&lt;/em&gt; contains the final result of the implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;start-project&lt;/code&gt; &lt;em&gt;branch&lt;/em&gt; contains the version that you should use to follow through with this article. It is highly recommended that you use the &lt;code&gt;start-project&lt;/code&gt; &lt;em&gt;branch&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The start project contains a &lt;code&gt;ContentView.swift&lt;/code&gt; file that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Defines a SwiftUI view.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contains a button that, when pressed, &lt;strong&gt;toggles the boolean value of&lt;/strong&gt; &lt;code&gt;isPresentingSheet&lt;/code&gt; and &lt;strong&gt;presents a modal sheet&lt;/strong&gt; using the &lt;code&gt;.sheet&lt;/code&gt; modifier. The content of the modal sheet is defined in a separate &lt;em&gt;struct&lt;/em&gt; called &lt;code&gt;ContentModalSheet&lt;/code&gt;. The &lt;code&gt;ContentView&lt;/code&gt; &lt;em&gt;struct&lt;/em&gt; also conforms to the &lt;em&gt;View&lt;/em&gt; &lt;em&gt;protocol&lt;/em&gt; and has a body property that returns a &lt;code&gt;VStack&lt;/code&gt; containing the button.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ContentView.swift&lt;/span&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="c1"&gt;// Used to toggle and present the modal sheet.&lt;/span&gt;
    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isPresentingSheet&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="kc"&gt;false&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;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="c1"&gt;// Returns a VStack containing the button.&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="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;presentSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;HStack&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;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"arrow.up"&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="s"&gt;"Present Sheet"&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;fontWeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;semibold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accentColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&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;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;isPresentingSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContentModalSheet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;init&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;padding&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;ContentView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Toggles the boolean value of isPresentingSheet and presents a modal sheet using the .sheet modifier. &lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;presentSheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;isPresentingSheet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&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;The start project also contains another file called &lt;code&gt;ContentModalSheet.swift&lt;/code&gt; that contains the &lt;em&gt;View&lt;/em&gt; to be presented.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Defines a view called &lt;code&gt;ContentModalSheet&lt;/code&gt;, which is presented as a modal sheet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Display the &lt;code&gt;Text&lt;/code&gt; "Showing Modal Sheet" and the &lt;code&gt;Button&lt;/code&gt; that dismisses the &lt;em&gt;sheet&lt;/em&gt; by using the &lt;em&gt;Environment&lt;/em&gt; &lt;code&gt;dismiss&lt;/code&gt; property and calling the &lt;code&gt;.callAsFunction&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentModalSheet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(\\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;dismissModalSheet&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;ContentModalSheet&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="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="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dismissModalSheet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callAsFunction&lt;/span&gt;&lt;span class="p"&gt;)&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;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"xmark"&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;fontWeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;semibold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;uiColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&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;frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;alignment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="kt"&gt;Spacer&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="s"&gt;"Showing Modal Sheet"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;Spacer&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;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create PresentationDetent extension
&lt;/h2&gt;

&lt;p&gt;A straightforward implementation of the &lt;code&gt;.presentationDetents()&lt;/code&gt; method sets the available detents/static properties and methods (&lt;em&gt;snap points&lt;/em&gt;) for enclosing &lt;em&gt;sheet&lt;/em&gt; presentations in different sizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.large&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.medium&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.custom&amp;lt;D&amp;gt;(D.Type)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.fraction(CGFloat)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.height(CGFloat)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the above properties and methods return a &lt;code&gt;PresentationDetent&lt;/code&gt; instance. Let's see this in practice in the bellow code by checking the &lt;code&gt;.presentationDetents([.medium, .height(420), .large])&lt;/code&gt; line of code.&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="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;presentSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;HStack&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;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"arrow.up"&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="s"&gt;"Present Sheet"&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;fontWeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;semibold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accentColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&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;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;isPresentingSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;ContentModalSheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presentationDetents&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;large&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 default, &lt;em&gt;sheets&lt;/em&gt; present the &lt;code&gt;PresentationDetent/large&lt;/code&gt; detent. If we want to change this behavior we can change this with two lines of code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a private property named &lt;code&gt;selectDetent&lt;/code&gt; of type &lt;code&gt;PresentationDetent&lt;/code&gt; and initializes it with a value of &lt;code&gt;.height(64)&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;selectDetent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PresentationDetent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&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;ol&gt;
&lt;li&gt;Add the &lt;code&gt;selection&lt;/code&gt; parameter to the &lt;code&gt;.presentationDetents&lt;/code&gt; method and assign it with &lt;code&gt;$selectDetent&lt;/code&gt; variable. The method will return the selected &lt;code&gt;PresentationDetent&lt;/code&gt; assigned to this variable.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Button... {}&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;isPresentingSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ContentModalSheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presentationDetents&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;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;large&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="nv"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;selectDetent&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;To explain a little bit further, a &lt;em&gt;detent&lt;/em&gt; is a position at which our modal presentation can &lt;em&gt;snap&lt;/em&gt; to. For example, if we have a modal presentation, we can define different &lt;em&gt;detents&lt;/em&gt; for displaying the &lt;em&gt;View&lt;/em&gt; in different sizes or styles.&lt;/p&gt;

&lt;p&gt;Now that we understood how detents work, let's extend our &lt;em&gt;detents&lt;/em&gt; to a separate file called &lt;code&gt;PresentationDetent+Extension&lt;/code&gt;, then add the following code to it.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;PresentationDetent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mediumBottomBar&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;medium&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;largeBottomBar&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;large&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code defines two &lt;em&gt;static&lt;/em&gt; properties in the &lt;code&gt;PresentationDetent&lt;/code&gt; &lt;em&gt;struct&lt;/em&gt; and assigns them the original values of the &lt;code&gt;medium&lt;/code&gt; and &lt;code&gt;large&lt;/code&gt; &lt;em&gt;static&lt;/em&gt; properties of the &lt;em&gt;struct&lt;/em&gt;. This can be &lt;strong&gt;good if we want to improve the context and nomenclature of our properties&lt;/strong&gt; and feature implementations.&lt;/p&gt;

&lt;p&gt;In the next section, we will go further and finally implements our custom property.&lt;/p&gt;

&lt;h2&gt;
  
  
  CustomPresentationDetent implementation
&lt;/h2&gt;

&lt;p&gt;To implement &lt;code&gt;CustomPresentationDetent&lt;/code&gt; for our modal presentation, we need to create a custom &lt;em&gt;struct&lt;/em&gt; that conforms with the &lt;em&gt;protocol&lt;/em&gt;. The &lt;em&gt;protocol&lt;/em&gt; contains a &lt;em&gt;static&lt;/em&gt; method that returns an &lt;em&gt;optional&lt;/em&gt; &lt;code&gt;CGFloat&lt;/code&gt;.&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;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&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;CGFloat&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, let's create our custom &lt;em&gt;struct&lt;/em&gt; and implements the &lt;em&gt;protocol&lt;/em&gt;.&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;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;BottomBarDetent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CustomPresentationDetent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Calculates and returns a height based on the context.&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&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;CGFloat&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxDetentValue&lt;/span&gt; &lt;span class="o"&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="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 on top of our &lt;em&gt;extension&lt;/em&gt; file, we can add a new property that uses our custom type.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;PresentationDetent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bottom&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="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BottomBarDetent&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And respectively in our existing &lt;code&gt;.presentationDetents&lt;/code&gt; method, we can update it to use our new custom properties &lt;code&gt;.bottom, .mediumBottomBar&lt;/code&gt;, and &lt;code&gt;.largeBottomBar&lt;/code&gt;.&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;// Button... {}&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;isPresentingSheet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ContentModalSheet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presentationDetents&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;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mediumBottomBar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;largeBottomBar&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="nv"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;selectDetent&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article provided a detailed explanation of how to use &lt;code&gt;CustomPresentationDetent&lt;/code&gt;. Now if necessary, create more flexible and customizable modal presentations in your future SwiftUI projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/amarildolucas/CustomPresentationDetent/tree/main"&gt;You can download the final project here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you enjoyed this article, please consider &lt;a href="https://www.buymeacoffee.com/amarildocodes"&gt;supporting me by offering me a coffee&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.buymeacoffee.com/amarildocodes"&gt;https://www.buymeacoffee.com/amarildocodes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading, and happy building! :)&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftui</category>
      <category>ios</category>
      <category>xcode</category>
    </item>
    <item>
      <title>Navigation App Architecture on Apple eyes</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Sat, 14 May 2022 20:48:12 +0000</pubDate>
      <link>https://forem.com/amarildo/navigation-app-architecture-on-apple-eyes-2ic7</link>
      <guid>https://forem.com/amarildo/navigation-app-architecture-on-apple-eyes-2ic7</guid>
      <description>&lt;p&gt;&lt;strong&gt;A visual on Apple human interface guidelines for navigation on iOS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are like me and love learning by seeing visuals or flows about some programming or UI/UX topics, I hope you enjoy this mind node that I created about how the Navigation should be on iOS on Apple eyes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JSQ3c-qU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/un0p3v3ldn2a6hn0u1l2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JSQ3c-qU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/un0p3v3ldn2a6hn0u1l2.png" alt="A visual on Apple human interface guidelines for navigation on iOS" width="880" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can download it and use it as your need. 🚀&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amarildo.codes/navigation-app-architecture-on-apple-eyes"&gt;https://amarildo.codes/navigation-app-architecture-on-apple-eyes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/navigation/"&gt;https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/navigation/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>swift</category>
      <category>swiftui</category>
      <category>xcode</category>
      <category>ios</category>
    </item>
    <item>
      <title>@discardableResult</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Fri, 27 Mar 2020 14:18:28 +0000</pubDate>
      <link>https://forem.com/amarildo/discardableresult-3b3a</link>
      <guid>https://forem.com/amarildo/discardableresult-3b3a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ignoring non-void function returns so they do not warn on unused results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are writing your code and have a couple of functions that return some values. But when you are invoking some of these functions you are not using the returning values and are getting warnings like this through your compiler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;warning:&lt;/code&gt; result of call to 'someFunction()' is unused&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So to avoid these warnings, your code starts looking like this:&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;let&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The warning was now suppressed and your console outputs the expected result. But you are feeling not happy about seeing your code with a lot of &lt;code&gt;let _&lt;/code&gt;. This can be prone to future errors. &lt;/p&gt;

&lt;h2&gt;
  
  
  👉🏿 You need &lt;code&gt;@discardableResult&lt;/code&gt;.
&lt;/h2&gt;

&lt;p&gt;In Swift annotating methods and functions with @discardableResult informs the compiler that a non-void return type should be consumed. So, ignored results do not raise warnings or errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;warning:&lt;/code&gt; result of call to 'someFunction()' is unused&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The @discardableResult attribute enables developers to indicate when their functions and methods produce a non-essential result and should not produce a warning.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;removeLast&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;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&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="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;The above function removes the last element of an &lt;code&gt;Array&lt;/code&gt;. When we call &lt;code&gt;array.removeLast()&lt;/code&gt; from &lt;code&gt;var array = [2, 4, 7, 0]&lt;/code&gt;, &lt;code&gt;array.removeLast()&lt;/code&gt; returns 0.&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;var&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&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="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// warning: result of call to 'removeLast()' is unused&lt;/span&gt;
&lt;span class="c1"&gt;// array.removeLast()&lt;/span&gt;
&lt;span class="c1"&gt;//      ^         ~~&lt;/span&gt;
&lt;span class="c1"&gt;// [2, 4, 7]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As our intention was just to remove the last element of the array and do nothing with the returned value, it makes sense to us to discard this value. So rather suppress the warning message with &lt;code&gt;let _ = array.removeLast()&lt;/code&gt;, we should use &lt;code&gt;@discardableResult&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the following snippet, we expect to be able to discard the return value after invoking &lt;code&gt;array.removeLast()&lt;/code&gt;.&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;extension&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;@discardableResult&lt;/span&gt;
    &lt;span class="k"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;removeLast&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;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&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="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;When we call &lt;code&gt;array.removeLast()&lt;/code&gt; again, we will not see the warning anymore.&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;var&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&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="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// [2, 4, 7]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  🙌🏿
&lt;/h1&gt;

</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>iOS CI/CD: Continuous Integration and Continuous Delivery Explained</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Tue, 01 Oct 2019 13:06:08 +0000</pubDate>
      <link>https://forem.com/semaphore/ios-ci-cd-continuous-integration-and-continuous-delivery-explained-17lf</link>
      <guid>https://forem.com/semaphore/ios-ci-cd-continuous-integration-and-continuous-delivery-explained-17lf</guid>
      <description>&lt;p&gt;Continuous integration and continuous delivery (&lt;a href="https://semaphoreci.com/cicd" rel="noopener noreferrer"&gt;CI/CD&lt;/a&gt;) is widely used by development teams, even in open-source communities. It offers a sustainable way to test and deploy code many times a day without the hurdle of doing it manually.&lt;/p&gt;

&lt;p&gt;In this guide, you'll learn the foundations of getting started with CI/CD for iOS. We'll learn about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The importance of CI/CD for iOS developers&lt;/li&gt;
&lt;li&gt;Principles of iOS CI/CD&lt;/li&gt;
&lt;li&gt;The top benefits of CI/CD for iOS&lt;/li&gt;
&lt;li&gt;Best practices to remember for iOS CI/CD&lt;/li&gt;
&lt;li&gt;An iOS CI/CD workflow example&lt;/li&gt;
&lt;li&gt;Getting started with CI/CD for iOS&lt;/li&gt;
&lt;li&gt;Choosing the right iOS CI/CD platform&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this article, you’ll be able to evaluate your current workflow, adopt the best CI/CD practices, and ship your iOS applications faster.  &lt;/p&gt;

&lt;h2&gt;The importance of CI/CD for iOS developers&lt;/h2&gt;

&lt;p&gt;CI/CD for iOS&lt;strong&gt; will save you days&lt;/strong&gt; of preparing app submissions, fixing critical bugs, and uploading screenshots to the App Store. Automating these processes means that any member of the team will be able to release bug fixes or updates. &lt;/p&gt;

&lt;p&gt;The CI/CD can check in and check out source code so all members on your team will be on the same page. Leading to better communication, increased app development quality, and more frequent releases. &lt;/p&gt;

&lt;h3&gt;The DevOps Role&lt;/h3&gt;

&lt;p&gt;DevOps is a cultural change in the organization where the operations and development teams join forces to &lt;a href="https://semaphoreci.com/blog/2017/07/27/what-is-the-difference-between-continuous-integration-continuous-deployment-and-continuous-delivery.html" rel="noopener noreferrer"&gt;continuously deliver&lt;/a&gt; high-quality software.&lt;/p&gt;

&lt;p&gt;Because teams employing DevOps ideals are focused on delivering value to users as quickly and efficiently as possible, &lt;a href="https://semaphoreci.com/continuous-integration" rel="noopener noreferrer"&gt;continuous integration&lt;/a&gt; and delivery is a natural extension of their operations.&lt;/p&gt;

&lt;p&gt;The end goal is to help iOS developers build and release apps at high velocity by defining a process for effective app delivery.&lt;/p&gt;

&lt;h2&gt;Principles of iOS CI/CD&lt;/h2&gt;

&lt;p&gt;One of the most important aspects of implementing CI/CD for iOS is learning about the principles that can increase the value of your current workflow:&lt;/p&gt;

&lt;h3&gt;Use Static Code Analysis&lt;/h3&gt;

&lt;p&gt;So that the build can fail early (in the event of serious coding errors), static code analysis should be the absolute &lt;strong&gt;first step in the build process&lt;/strong&gt;. This way, you can fix the issues as soon they are found by the server.&lt;/p&gt;

&lt;h3&gt;Keep the Code Deployable&lt;/h3&gt;

&lt;p&gt;Once the &lt;a href="https://medium.com/dailyjs/why-you-should-always-use-a-linter-and-or-pretty-formatter-bb5471115a76" rel="noopener noreferrer"&gt;linter&lt;/a&gt; step is passed, we can move on to the building and compiling of the source code. The last step in the app build process should be to generate the archive to be submitted to &lt;a href="https://itunesconnect.apple.com/login" rel="noopener noreferrer"&gt;iTunes Connect&lt;/a&gt;. In the case of iOS, it should be an IPA file.&lt;/p&gt;

&lt;h3&gt;Notify your Team&lt;/h3&gt;

&lt;p&gt;Any developer can deploy any version of the app to any environment at a push of a button. Once the build is finished, it’s important to send a notification to other developers with the status of the build. This can be an email, Slack message, or similar notification service. The &lt;a href="https://semaphoreci.com/blog/cicd-pipeline" rel="noopener noreferrer"&gt;iOS CI/CD pipeline&lt;/a&gt; should trigger this notification at the end of every build.&lt;/p&gt;

&lt;h3&gt;Design for Iterative Releases&lt;/h3&gt;

&lt;p&gt;Have a well-defined pipeline that focuses on automated delivery. Implement static analytics on your source code to detect issues or crashes (even in production).&lt;/p&gt;

&lt;h2&gt;The top benefits of CI/CD for iOS&lt;/h2&gt;

&lt;p&gt;Aside from making your previous iOS development process more efficient, implementing a CI/CD pipeline helps your team:&lt;/p&gt;

&lt;h3&gt;1. Build faster&lt;/h3&gt;

&lt;p&gt;A continuous and automated development cycle helps mobile development teams make high-value releases faster. &lt;/p&gt;

&lt;h3&gt;2. Detect problems early&lt;/h3&gt;

&lt;p&gt;A continuous integration pipeline can run test suites on every code change. Thus, problems can be spotted before they can reach production.&lt;/p&gt;

&lt;h3&gt;3. Provide effective feedback &lt;/h3&gt;

&lt;p&gt;In a continuous integration workflow, the entire team can view and monitor source code activity. When new problems appear, the team members that introduced the failure are automatically notified. &lt;/p&gt;

&lt;h3&gt;4. Automate the testing process &lt;/h3&gt;

&lt;p&gt;Manually testing iOS apps on a simulator or multiple devices is a time-consuming process. In a CI/CD workflow, the process is automatic and straightforward. Simply configure the devices and simulators into the server workflow and let your pipeline do the work for you.&lt;/p&gt;

&lt;h3&gt;5. Build deployment logs&lt;/h3&gt;

&lt;p&gt;In a CI/CD pipeline, all build deployments are logged. This means that at any given time, you can identify the exact point where your app failed.&lt;/p&gt;

&lt;h2&gt;Best practices to remember for iOS CI/CD &lt;/h2&gt;

&lt;p&gt;When implementing a CI/CD workflow for iOS development, it's vital you adhere to standard best practices. Why? The guidelines below are designed to help you push high-quality code with every release.&lt;/p&gt;

&lt;h3&gt;1. Keep your Pipeline Fast&lt;/h3&gt;

&lt;p&gt;Always improve the quality of your pipeline by inspecting its configuration, improving build times, removing any unnecessary code or assets, configuring the right environments, and removing any bottlenecks causing issues on the deploy process.&lt;/p&gt;

&lt;h3&gt;2. Run Code Analysis Early&lt;/h3&gt;

&lt;p&gt;Fail fast: Include unit tests and linters early in the pipeline.&lt;/p&gt;

&lt;h3&gt;3. Separate Build Configurations&lt;/h3&gt;

&lt;p&gt;Use profiles to separate build configurations. Internal and testing builds are different from the builds for your users. By default, an iOS app includes Debug and Release build configurations. It makes sense to add Test, Staging and Production builds.&lt;/p&gt;

&lt;h3&gt;4. Automate Your Builds&lt;/h3&gt;

&lt;p&gt;Compiling and building an iOS app takes a great deal of time. Using CI/CD workflow you can automate the process and save time.&lt;/p&gt;

&lt;h3&gt;5. Deploy Only Through the Pipeline&lt;/h3&gt;

&lt;p&gt;The pipeline is configured to help and enforce best practices of CI/CD for your development cycle. Avoid at all cost manual deploys. &lt;/p&gt;

&lt;p&gt;Making your code run through your pipeline requires each change to conform with your code standards and styles. This mechanism safeguards your codebase from untrusted code.&lt;/p&gt;

&lt;h3&gt;6. Maintain Similar Environments&lt;/h3&gt;

&lt;p&gt;If possible, try to maintain similar pipelines in all your environments. Changes that pass the requirements of one environment should pass in another. This also includes feature branches.&lt;/p&gt;

&lt;h3&gt;7. Monitor the Pipeline&lt;/h3&gt;

&lt;p&gt;Apps are unpredictable. No matter how cool you think your code is, the app can fail for a lot of reasons. Therefore, you'll need to proactively monitor your deploys throughout the pipeline so you can catch problems before they reach the App Store.&lt;/p&gt;

&lt;h2&gt;An iOS CI/CD workflow example &lt;/h2&gt;

&lt;p&gt;&lt;a href="https://s2blog.wpengine.com/wp-content/uploads/2019/09/ios-workflow-raw-745d17ba224c10f71963a21bee42c7d1803a2f649a810472de4576e65056e892.png" 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%2Fs2blog.wpengine.com%2Fwp-content%2Fuploads%2F2019%2F09%2Fios-workflow-raw-745d17ba224c10f71963a21bee42c7d1803a2f649a810472de4576e65056e892-1024x512.png" alt="example iOS ci/cd pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After understanding and adopting essential CI/CD principles, the next step is to set up your pipeline. One of the more painful parts of iOS development is iterative releases. It's tedious and time-consuming. The role of CI/CD here is to automate all of these steps.&lt;/p&gt;

&lt;p&gt;Before implementing CI/CD, a typical release to the App Store looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out source code from some remote repository (GitHub, Bitbucket, GitLab, etc.).&lt;/li&gt;
&lt;li&gt;Do some static analysis of the code using SwiftLint, for example.&lt;/li&gt;
&lt;li&gt;Compile and build your iOS app in a simulator or device to check that everything is running as expected.&lt;/li&gt;
&lt;li&gt;Run unit, UI or other kinds of tests.&lt;/li&gt;
&lt;li&gt;Code signing and archive your app.&lt;/li&gt;
&lt;li&gt;Submit your app to iTunes Connect.&lt;/li&gt;
&lt;li&gt;Notify users about your release.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process can be error-prone; you may experience merge conflicts and poor management of versions (as this is done manually by each developer). &lt;/p&gt;

&lt;p&gt;Fortunately, we can improve it with automation. When we use an iOS CI/CD pipeline, our workflow looks more like this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code the application changes with Xcode. &lt;/li&gt;
&lt;li&gt;When the code is ready for integration, it automatically pushes to a Git repository. &lt;/li&gt;
&lt;li&gt;Next, CI triggers the execution of test cases that will confirm the code is ready for release. &lt;/li&gt;
&lt;li&gt;Finally, the release pipeline triggers to deploy the archive produced in the CI stage, and a build is released with TestFlight.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See how the iOS developer has far less to do with CI/CD? That’s the beauty of automation.&lt;/p&gt;

&lt;h2&gt;Getting Started with iOS CI/CD &lt;/h2&gt;

&lt;p&gt;To integrate CI/CD into your iOS development process, start by exploring what things can make your team's job easier. You need to understand and collect information about your current workflow and provide feedback to the team until you have defined a process for your pipeline. &lt;/p&gt;

&lt;p&gt;Using this information, your team can evaluate and define how to automate the current workflow to lead to a better development lifecycle. Optimizing and automating the current process should be the priority.&lt;/p&gt;

&lt;p&gt;Ultimately, this approach &lt;strong&gt;increases transparency through all your team&lt;/strong&gt;. When your iOS CI/CD pipeline is set up, your entire team will know what’s going on with the builds and will receive the latest results of tests, which means they can move on to resolving new issues. &lt;/p&gt;

&lt;p&gt;This process allows developers to stay focused on writing code and observing the app's behavior. Meanwhile, product stakeholders have  access to updated metrics. Code changes and tests are available for review at any time.&lt;/p&gt;

&lt;p&gt;The lesson here is that, as a faster feedback loop emerges, each member of the team can learn from each other and take responsibility for the code that is shipped.&lt;/p&gt;

&lt;h2&gt;Choosing the Right iOS CI/CD Platform&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Self-hosted CI/CD solutions&lt;/strong&gt; require owning hardware and setting up infrastructure. Maintenance becomes a big endeavor.&lt;/p&gt;

&lt;p&gt;Software-as-a-service (SaaS) solutions, on the other hand, offer cross-platform capabilities with zero maintenance&lt;/p&gt;

&lt;p&gt;These&lt;strong&gt; cloud-based CI/CD tools&lt;/strong&gt; are easy to set up and all the hardware and software maintenance is managed by the service provider. Developers can skip a lot of tedious or repetitive tasks, such as code signing and publishing.&lt;/p&gt;

&lt;p&gt;Cloud-based CI/CD also comes with a big advantage: &lt;strong&gt;it unifies your team around a single platform&lt;/strong&gt;, mobilizing your iOS, Android and web developers within a consistent tool.&lt;/p&gt;

&lt;h2&gt;Summing Up&lt;/h2&gt;

&lt;p&gt;A well-defined process and the right CI/CD tools will make  your iOS development cycle faster and more efficient.&lt;/p&gt;

&lt;p&gt;If you want to explore CI/CD for iOS in a more hands-on way, check out our tutorial on &lt;a href="https://semaphoreci.com/blog/tutorial-ios-cicd" rel="noopener noreferrer"&gt;building, testing, &amp;amp; deploying an iOS App with CI/CD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have any questions about this guide? Don't hesitate to reach out to us on Twitter &lt;a href="https://twitter.com/semaphoreci" rel="noopener noreferrer"&gt;@semaphoreci&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Tutorial: Build, Test, &amp; Deploy an iOS App with CI/CD</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Fri, 20 Sep 2019 21:36:59 +0000</pubDate>
      <link>https://forem.com/semaphore/tutorial-build-test-deploy-an-ios-app-with-ci-cd-37k4</link>
      <guid>https://forem.com/semaphore/tutorial-build-test-deploy-an-ios-app-with-ci-cd-37k4</guid>
      <description>&lt;p&gt;When we develop iOS apps, we usually manage the app publication process using the Xcode Organizer. Then we sign, test, build, archive, submit, change versions, submit new builds again and again to the TestFlight or AppStore.&lt;/p&gt;

&lt;p&gt;If we generate our builds daily, this process is tedious and tiring. Sooner or later, you will ask yourself:&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;How can we automate this entire process?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://semaphoreci.com/ios-continuous-integration" rel="noopener noreferrer"&gt;Continuous Integration and Continuous Delivery (CI/CD) for iOS&lt;/a&gt; enable us to improve our build deploys. We’re able to release updates at any time in a sustainable way without the hurdle of doing it manually every time. We don’t need to run all our tests when we add new code or take a trial and error approach before pushing a commit to our repository.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll learn how to automatically deploy our apps to the TestFlight using Semaphore as our CI/CD platform. When we push our code to our remote repository, Semaphore will test, build, deploy and generate screenshots of our app.&lt;/p&gt;

&lt;p&gt;To make things simple, we’ve divided this tutorial into two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://semaphoreci.com/continuous-integration" rel="noopener noreferrer"&gt;&lt;strong&gt;Continuous integration&lt;/strong&gt;&lt;/a&gt;: build, test and archive the app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://semaphoreci.com/cicd" rel="noopener noreferrer"&gt;&lt;strong&gt;Continuous deployment&lt;/strong&gt;&lt;/a&gt;: submit the build to Testflight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will start by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up our repository in GitHub.&lt;/li&gt;
&lt;li&gt;Signing up for Semaphore CI.&lt;/li&gt;
&lt;li&gt;Linking our GitHub repository to Semaphore CI Project.&lt;/li&gt;
&lt;li&gt;Configuring our first &lt;a href="https://semaphoreci.com/blog/cicd-pipeline" rel="noopener noreferrer"&gt;CI/CD pipeline&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Improving our CI/CD pipeline with Fastlane.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
&lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#continuous-integration-with-semaphore" rel="noopener noreferrer"&gt;&lt;/a&gt;Continuous integration with Semaphore&lt;/h2&gt;

&lt;p&gt;You will need an &lt;a href="https://semaphoreci.com/product/ios" rel="noopener noreferrer"&gt;iOS&lt;/a&gt; app to configure our Continuous Integration and Delivery pipeline. Then, you will need to configure a new repository.&lt;/p&gt;

&lt;p&gt;We will use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt;: for version control.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; account to manage our repository.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode 11 with Swift 5.1&lt;/a&gt; as our development tools.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/swiftui/" rel="noopener noreferrer"&gt;SwiftUI&lt;/a&gt; to build our user interface.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/documentation/xctest" rel="noopener noreferrer"&gt;XCTest&lt;/a&gt; to create and run unit tests and UI tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; SwiftUI previews and inspectors are only available when running on macOS Catalina 10.15.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt; You can download the project and follow along with this tutorial, or create a new iOS &lt;strong&gt;Single View Application&lt;/strong&gt; project from scratch. &lt;/p&gt;

&lt;p&gt; &lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore Demo iOS Swift Xcode &lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Xcode will set up Git automatically for you since it is checked by default. Otherwise, you can set up manually by running &lt;code&gt;git init&lt;/code&gt; in the root project directory in the terminal.&lt;/p&gt;

&lt;p&gt;You can also check your new git repository by writing &lt;code&gt;git status&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git status

On branch master
nothing to commit, working tree clean&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Build and run the app on the simulator. If you have unit tests and UI tests in the project, run your test cases first in the Test navigator. If everything looks right, push the code to the GitHub repository. Nearly every new iOS project runs without problems the first time. If you run into a problem, you can always grab the &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore demo app from Github&lt;/a&gt; that we are using to following through this tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Semaphore pipeline is configured to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run all unit and UI tests.&lt;/li&gt;
&lt;li&gt;Build the app and generate an &lt;code&gt;ipa&lt;/code&gt; archive.&lt;/li&gt;
&lt;li&gt;Generate automated App Store screenshots.&lt;/li&gt;
&lt;li&gt;Upload the archived &lt;code&gt;ipa&lt;/code&gt; and screenshots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end of this tutorial you will achieve a result like in the below image:&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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67.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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67.png" alt="semaphore CI pipeline for iOS"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h3&gt;Setting up Semaphore for an iOS project&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Go to&lt;/strong&gt; &lt;a href="https://semaphoreci.com/login" rel="noopener noreferrer"&gt;https://semaphoreci.com/login&lt;/a&gt; and log in with your GitHub account.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;+ Projects&lt;/strong&gt; to add the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/0d7c5aaa507385c9e6ab40aca6c071ede1387afd/68747470733a2f2f616d6172696c646f6c756361732e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f53656d6170686f726543492f696f732d63692d63642f436170747572612b64652b54656c612b323031392d30392d31372b61254343253830732b30382e34382e32372e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/0d7c5aaa507385c9e6ab40aca6c071ede1387afd/68747470733a2f2f616d6172696c646f6c756361732e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f53656d6170686f726543492f696f732d63692d63642f436170747572612b64652b54656c612b323031392d30392d31372b61254343253830732b30382e34382e32372e706e67" alt="screenshot of creating a new project in semaphore for iOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Semaphore will list GitHub repositories. If you haven't pushed the code yet, you will need to push it so you can see the repository listed.&lt;/p&gt;

&lt;p&gt;Follow the GitHub instructions after you created a new repository, which is the most important part:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git remote add origin git@github.com:amarildolucas/ios-semaphore-intro.git
$ git add -A
$ git commit -m "First commit"
$ git push -u origin master&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;This will push your code to GitHub.&lt;/strong&gt; Since this is likely part of your day-to-day workflow, I won't go into too many details here.  Remember, if you don't want to start a new project from scratch, you can just fork the &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore iOS demo app&lt;/a&gt; as recommended above. &lt;/p&gt;

&lt;p&gt;Now, in Semaphore, connect the new repository. Refresh the list to see the repository, if needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/585887c911d351905be02aa6c39382c1fe1bdada/68747470733a2f2f616d6172696c646f6c756361732e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f53656d6170686f726543492f696f732d63692d63642f436170747572612b64652b54656c612b323031392d30392d31372b61254343253830732b30382e35302e32352e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/585887c911d351905be02aa6c39382c1fe1bdada/68747470733a2f2f616d6172696c646f6c756361732e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f53656d6170686f726543492f696f732d63692d63642f436170747572612b64652b54656c612b323031392d30392d31372b61254343253830732b30382e35302e32352e706e67" alt="screenshot of adding a repository from GitHub in Semaphore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you connected the repository to Semaphore, &lt;strong&gt;select your project's main language&lt;/strong&gt;. Choose "Swift" to continue with an iOS setup.&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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d6c616e67756167652d776f726b666c6f772e706e67.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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d6c616e67756167652d776f726b666c6f772e706e67.png" alt="screenshot of choosing a starter workflow for Swift in Semaphore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see that Semaphore created a new file to be committed to our repository.  If you chose the &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore demo app&lt;/a&gt; to follow through this tutorial, find the configured pipeline inside the root directory &lt;code&gt;.semaphore/semaphore.yml.&lt;/code&gt;. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Use the latest stable version of Semaphore 2.0 YML syntax:
version: v1.0

# Name your pipeline. If you choose to connect multiple pipelines with
# promotions, the pipeline name will help you differentiate between
# them. For example, you might have a build phase and a delivery phase.
# For more information on promotions, see:
# https://docs.semaphoreci.com/article/67-deploying-with-promotions
name: Tallest Towers

# The agent defines the environment in which your CI runs. It is a combination
# of a machine type and an operating system image. For a project built with
# Xcode you must use one of the Apple machine types, coupled with a macOS image
# running either Xcode 10 or Xcode 11.
# See https://docs.semaphoreci.com/article/20-machine-types
# https://docs.semaphoreci.com/article/161-macos-mojave-xcode-10-image and
# https://docs.semaphoreci.com/article/162-macos-mojave-xcode-11-image
agent:
  machine:
    type: a1-standard-4
    os_image: macos-mojave-xcode11

# Blocks are the heart of a pipeline and are executed sequentially. Each block
# has a task that defines one or more parallel jobs. Jobs define commands that
# should be executed by the pipeline.
# See https://docs.semaphoreci.com/article/62-concepts
blocks:
  - name: Run tests
    task:
      # Set environment variables that your project requires.
      # See https://docs.semaphoreci.com/article/66-environment-variables-and-secrets
      env_vars:
        - name: LANG
          value: en_US.UTF-8
      prologue:
        commands:
          # Download source code from GitHub.
          - checkout

          # Restore dependencies from the cache. This command will not fail in
          # case of a cache miss. In case of a cache hit, bundle  install will
          # complete in about a second.
          # See https://docs.semaphoreci.com/article/68-caching-dependencies
          - cache restore
          - bundle install --path vendor/bundle
          - cache store
      jobs:
        - name: Test
          commands:
            # Select an Xcode version.
            # See https://docs.semaphoreci.com/article/161-macos-mojave-xcode-10-image and
            # https://docs.semaphoreci.com/article/162-macos-mojave-xcode-11-image
            - bundle exec xcversion select 11.2.1

            # Run tests of iOS and Mac app on a simulator or connected device.
            # See https://docs.fastlane.tools/actions/scan/
            - bundle exec fastlane test

  - name: Build app
    task:
      env_vars:
        - name: LANG
          value: en_US.UTF-8
      secrets:
        # Make the SSH key for the certificate repository and the MATCH_PASSWORD
        # environment variable available.
        # See https://docs.semaphoreci.com/article/109-using-private-dependencies
        - name: match-secrets
      prologue:
        commands:
          # Add the key for the match certificate repository to ssh
          # See https://docs.semaphoreci.com/article/109-using-private-dependencies
          - chmod 0600 ~/.ssh/*
          # Add the key to the ssh agent:
          - ssh-add ~/.ssh/*
          # Continue with checkout as normal
          - checkout
          - cache restore
          - bundle install --path vendor/bundle
          - cache store
      jobs:
        - name: Build
          commands:
            - bundle exec xcversion select 11.2.1
            - bundle exec fastlane build

            # Upload the IPA file as a job artifact.
            # See https://docs.semaphoreci.com/article/155-artifacts
            - artifact push job build/TallestTowers.ipa
  - name: Take screenshots
    task:
      env_vars:
        - name: LANG
          value: en_US.UTF-8
      prologue:
        commands:
          - checkout
          - cache restore
          - bundle install --path vendor/bundle
          - cache store
      jobs:
        - name: Screenshots
          commands:
            - bundle exec xcversion select 11.2.1
            - bundle exec fastlane screenshots

            # Upload the screenshots directory as a project artifact.
            # See https://docs.semaphoreci.com/article/155-artifacts
            - artifact push job screenshots&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every Semaphore pipeline starts with the &lt;strong&gt;version&lt;/strong&gt;, &lt;strong&gt;name&lt;/strong&gt; and &lt;strong&gt;agent&lt;/strong&gt;. An agent is a virtual machine that powers the pipeline. Let's understand the above file, which defines our pipeline workflow.&lt;/p&gt;

&lt;h4&gt;Version&lt;/h4&gt;

&lt;p&gt;The first line &lt;code&gt;version: v1.0&lt;/code&gt; uses the latest stable version of Semaphore 2.0 YML syntax. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;version: v1.0
name: Tallest Towers&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By default, they are named with the language-specific template that you chose. This is our pipeline &lt;strong&gt;name&lt;/strong&gt;. &lt;/p&gt;

&lt;h4&gt;Agent&lt;/h4&gt;

&lt;p&gt;Next, we have an &lt;code&gt;agent&lt;/code&gt;. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;agent:
  machine:
    type: a1-standard-4
    os_image: macos-mojave-xcode11&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An agent defines the environment in which your code will run. There are multiple available machine types and operating system images. This means that on the Semaphore side, your code will be built in a hosted &lt;strong&gt;macos-mojave&lt;/strong&gt; &lt;a href="https://docs.semaphoreci.com/article/20-machine-types#apple-machine-type" rel="noopener noreferrer"&gt;machine&lt;/a&gt;.  This is a customized image with Xcode 11 preinstalled. &lt;/p&gt;

&lt;p&gt;In our case, &lt;code&gt;a1-standard-4&lt;/code&gt; is our machine name with 4 virtual CPUs, 8 GB of memory and 50 GB of disk. &lt;/p&gt;

&lt;h4&gt;Blocks&lt;/h4&gt;

&lt;p&gt;Blocks define actions for the pipeline. They are executed sequentially and are probably the most important part of this file. Each block has a task that defines one or more jobs, and these jobs define the commands to execute. Once all jobs in a block are complete, the next block begins. Essentially, blocks define your Continuous Integration and Continuous Delivery pipeline flow. &lt;/p&gt;

&lt;p&gt; In this file we have 3 blocks named ** Run tests**, &lt;strong&gt;Build app&lt;/strong&gt; and ** Take screenshots**. All defining a task with some jobs. These jobs define some commands to run, for example &lt;code&gt;bundle exec xcversion select 11.2.1 &lt;/code&gt;. Below is a more descriptive explanation for the job named &lt;em&gt;Test&lt;/em&gt; inside &lt;em&gt;Run tests&lt;/em&gt; block: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;bundle exec xcversion select 11.2.1 &lt;/code&gt; selects an Xcode version.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bundle exec fastlane test&lt;/code&gt; run tests of iOS and Mac app on a simulator or connected device. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The first block run all our unit and UI tests.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- name: Run tests
  task:
    env_vars:
      - name: LANG
        value: en_US.UTF-8
    prologue:
      commands:
        - checkout
        - cache restore
        - bundle install --path vendor/bundle
        - cache store
    jobs:
      - name: Test
        commands:
          - bundle exec xcversion select 11.2.1
          - bundle exec fastlane test&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;checkout&lt;/code&gt; command download source code from GitHub. The next commands, restore dependencies from the cache and install it. Finally, we select the Xcode version of the project and run the tests using &lt;a href="https://fastlane.tools/" rel="noopener noreferrer"&gt;Fastlane&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The next block build the app and generates an &lt;code&gt;ipa&lt;/code&gt; archive.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- name: Build app
  task:
    env_vars:
      - name: LANG
        value: en_US.UTF-8
    secrets:
      - name: match-secrets
    prologue:
      commands:
        - chmod 0600 ~/.ssh/*
        - ssh-add ~/.ssh/*
        - checkout
        - cache restore
        - bundle install --path vendor/bundle
        - cache store
    jobs:
      - name: Build
        commands:
          - bundle exec xcversion select 11.2.1
          - bundle exec fastlane build
          - artifact push job build/TallestTowers.ipa&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is very similar to the previous block. The commands inside this block configure our secrets, sign our app and upload it to &lt;a href="https://developer.apple.com/testflight/" rel="noopener noreferrer"&gt;TestFlight&lt;/a&gt; using Fastlane. We will go more in-depth about the other commands and Fastlane later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The last block capture and upload our app screenshots.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- name: Take screenshots
  task:
    env_vars:
      - name: LANG
        value: en_US.UTF-8
    prologue:
      commands:
        - checkout
        - cache restore
        - bundle install --path vendor/bundle
        - cache store
    jobs:
      - name: Screenshots
        commands:
          - bundle exec xcversion select 11.2.1
          - bundle exec fastlane screenshots
          - artifact push job screenshots&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that we repeat some commands like checkout, cache, etc, to get the necessary files from our repositories and dependencies. &lt;/p&gt;

&lt;p&gt;To commit your file, tap the button &lt;strong&gt;Run this workflow&lt;/strong&gt;. Also, pay attention to the fact that you can customize the default configuration before running by clicking on the &lt;em&gt;Customize it first&lt;/em&gt; link.&lt;/p&gt;

&lt;p&gt;Is everything green &lt;strong&gt;(Passed)&lt;/strong&gt;? You did it! 🎉&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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67-1.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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67-1.png" alt="screenshot of successful commit in semaphore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have a working setup for a real workflow that makes it easy for iOS developers entering the Continuous Delivery stage. After running the code, everything shows a “Passed” message in green. Go further and see the output of every step by tapping in your commit message or job name in the Semaphore dashboard to understand everything that happened in the backend of the console while running the pipeline steps.&lt;/p&gt;

&lt;p&gt;We can even have more blocks if we want. For example, a block to create changelog files of build versions or to send notifications on Slack, etc. This all depends on you and your pipeline strategy. So, now that you understand the file and how the integration process works, let’s understand our deployment process in depth.&lt;/p&gt;

&lt;p&gt;Before doing it, let’s make a quick overview of Continuous Integration. In this process, we commit our changes to the main code branch that triggers an automated code to build and run. Every &lt;code&gt;git push origin branch&lt;/code&gt; will trigger the automated process defined in the &lt;code&gt;semaphore.yml&lt;/code&gt; configuration file. This way we focus on our work rather than manually build and test code every time we do changes.&lt;/p&gt;

&lt;p&gt;Continuous Integration helps us archive a build that can be deployed and the automated tests check every tested code to be safe to deploy.&lt;/p&gt;

&lt;h2&gt;
&lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#continuous-deployment-with-semaphore" rel="noopener noreferrer"&gt;&lt;/a&gt;Continuous Deployment with Semaphore&lt;/h2&gt;

&lt;p&gt;Our code changes continuously while working on our apps. In practice, we deploy several versions of our apps, sometimes even on the same day. Rather, to fix bugs, add new features, refactoring some code, etc. It’s an endless cycle. Continuous Delivery is exactly this process. If we configure our project to trigger our defined pipeline automatically and fully automate the entire process of push code from our repository to production, the process is called Continuous Deployment.&lt;/p&gt;

&lt;p&gt;We want to define our pipeline with steps to do Continuous Deployment, so we can focus only on our code while working in small iterations and always keep the code in a deployable state.&lt;/p&gt;

&lt;p&gt;If you forked the &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore demo app&lt;/a&gt; you got all of this out of the box.&lt;/p&gt;

&lt;p&gt;Make sure that you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configured Fastlane to automate deployments and releases (Continuous Deployment).&lt;/li&gt;
&lt;li&gt;Added a block to build and run our unit and UI tests.&lt;/li&gt;
&lt;li&gt;Added a block with steps to build and deploy our app to TestFlight.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fastlane makes our Continuous Deployment life a bit easier. You may know it as is vastly used for deployment of apps to the App Store.&lt;/p&gt;

&lt;p&gt;If you don’t have Fastlane installed, you will need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Fastlane.&lt;/li&gt;
&lt;li&gt;Follow the instructions of configuring Fastlane files.&lt;/li&gt;
&lt;li&gt;Test if everything is working right.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want a quick setup help, you can see the files that we use in the configuration of the Semaphore Demo iOS Swift app &lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#" rel="noopener noreferrer"&gt;here&lt;/a&gt;. These files are added after we install and run Fastlane for the first time. To understand more about the process of Fastlane installation and configuration you should read this &lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#" rel="noopener noreferrer"&gt;introductory article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;fastlane init&lt;/code&gt; in the terminal after installation and follow the instructions.&lt;/p&gt;

&lt;p&gt;As we will automate our deployment of build distributions to TestFlight, you will need to have these steps finished:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your new app configured on the Apple Dev Center.&lt;/li&gt;
&lt;li&gt;Your new app available in App Store Connect.&lt;/li&gt;
&lt;li&gt;A successfully generated Fastlane configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, as an iOS Developer, I think that is your day to day for every new app. So, we will not enter in details here.&lt;/p&gt;

&lt;p&gt;This is everything we need to set up and deploy our first build with Continuous Deployment. In case you’re blocked in some steps, check the code of &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore Demo for iOS&lt;/a&gt; again to guide you, it is very specific and self-explanatory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ensure that Xcode “automatically manage signing” it’s unchecked in Xcode when you work with Fastlane. And that your Signing (Release) contains the match AppStore provisioning profile selected if you had a Match file.&lt;/p&gt;

&lt;h3&gt;
&lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#configure-your-keys-and-secrets" rel="noopener noreferrer"&gt;&lt;/a&gt;Configure your keys and secrets&lt;/h3&gt;

&lt;p&gt;Now that we have configured Fastlane, we must also provide a way for Semaphore CI to access the Git certificates repository and the Apple Developer portal.&lt;/p&gt;

&lt;p&gt;Because we will access a private repository, we need to create a deploy key and add it to Semaphore CI secrets. This typically happens over &lt;a href="https://en.wikipedia.org/wiki/Secure_Shell" rel="noopener noreferrer"&gt;SSH&lt;/a&gt;. If you are not familiar with SSH, &lt;a href="https://docs.semaphoreci.com/article/109-using-private-dependencies" rel="noopener noreferrer"&gt;this article&lt;/a&gt; walks you through the process to create, add and manage SSH keys to use in your pipeline.&lt;/p&gt;

&lt;p&gt;Also, I recommend this &lt;a href="https://help.github.com/en/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub article&lt;/a&gt; on generating a new SSH key.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd ~/.ssh
$ ssh-keygen -t rsa -f id_rsa_semaphoreci&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After generating the key, you will need to connect the SSH key to the project or user. Deploy your key to GitHub to grant access to your private repository.&lt;/p&gt;

&lt;p&gt;Also, let’s store the deploy key as a secret file in the Semaphore CI environment.&lt;/p&gt;

&lt;p&gt;Open the &lt;strong&gt;Semaphore Dashboard&lt;/strong&gt; for your Organization. On the left sidebar find the &lt;strong&gt;Configuration&lt;/strong&gt; section and click &lt;strong&gt;Secrets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/6b219848ba565f420fc207150f6efff907367d3c/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d736964656261722d736563726574732e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/6b219848ba565f420fc207150f6efff907367d3c/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d736964656261722d736563726574732e706e67" alt="Configuration section of the Semaphore CI dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To store the deploy key as a secret file in the Semaphore environment, click &lt;strong&gt;Create a new Secret&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/22d699ed144a11e2d490176495c62aa0f72ba845/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d6372656174652d6e65772d7365637265742e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/22d699ed144a11e2d490176495c62aa0f72ba845/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d6372656174652d6e65772d7365637265742e706e67" alt="create new secret in Semaphore Ci 2.0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name the secret as &lt;code&gt;match-secrets&lt;/code&gt; than enter your environment variables name and value to match Semaphore and Fastlane configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MATCH_GIT_URL&lt;/strong&gt;: your SSH Git URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MATCH_PASSWORD&lt;/strong&gt;: password for decryption of the match certificates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FASTLANE_USER&lt;/strong&gt;: App Store developer’s Apple ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FASTLANE_PASSWORD&lt;/strong&gt;: App Store developer’s password.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enter a destination file path &lt;code&gt;/Users/semaphore/.ssh/match-secrets&lt;/code&gt; to upload the SSH key that you previously generated &lt;code&gt;id_rsa_semaphoreci&lt;/code&gt; on your computer. Click &lt;strong&gt;Save Changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/fec1a41511a7be2e227e695acee6a2d68f016e27/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d736563726574732d636f6e6669672e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/fec1a41511a7be2e227e695acee6a2d68f016e27/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d736563726574732d636f6e6669672e706e67" alt="Entering the destination file in the iOS CI/CD tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This created the file &lt;code&gt;~/.ssh/match-secrets&lt;/code&gt; with necessary environment variables and made it accessible in Semaphore CI jobs.&lt;/p&gt;

&lt;p&gt;Now that you created your secret key, go to your &lt;strong&gt;Semaphore project&lt;/strong&gt; page, click &lt;strong&gt;Edit workflow button&lt;/strong&gt;, select block to which you want to connect secret, in your case is the &lt;code&gt;Build app&lt;/code&gt; block. On the right sidebar, scroll to &lt;strong&gt;Secrets&lt;/strong&gt; section, click the arrow button and check the secret that you previously created &lt;code&gt;match-secrets&lt;/code&gt;. Click &lt;strong&gt;Run the workflow&lt;/strong&gt; button to add the secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/6d116aec60ab9abd35f3c30bb736cf193cdb3417/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d776f726b666c6f772e706e67" rel="noreferrer noopener"&gt;&lt;img src="https://camo.githubusercontent.com/6d116aec60ab9abd35f3c30bb736cf193cdb3417/68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d2d776f726b666c6f772e706e67" alt="Running the workflow in Semaphore CI dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running this command, you will find your secrets inside the Semaphore Dashboard Secrets.&lt;/p&gt;

&lt;p&gt;Our &lt;em&gt;Build app&lt;/em&gt; block will look like below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- name: Build app
  task:
    env_vars:
      - name: LANG
        value: en_US.UTF-8
    secrets:
      - name: match-secrets
    prologue:
      commands:
        - chmod 0600 ~/.ssh/*
        - ssh-add ~/.ssh/match-secrets&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s explain some commands that we repeated in our pipeline blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cache restore&lt;/strong&gt;: restores an archive that matches any given key. In case of a cache hit, retrieves the archive and make it available at its original path in the job environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bundle install&lt;/strong&gt;: installs all Fastlane dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cache store&lt;/strong&gt;: archives a file or directory specified by the path and associates it with a given key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Chmod" rel="noopener noreferrer"&gt;chmod&lt;/a&gt;&lt;/strong&gt; 0600 &lt;code&gt;~/.ssh/*&lt;/code&gt;: reads and writes in files if it is the owner. It is all about permissions! You should be familiar with it in UNIX-like systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ssh-add&lt;/strong&gt; &lt;code&gt;~/.ssh/match-secrets&lt;/code&gt;: gives the path of the key file as an argument to ssh-add to add the generated keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;secrets:&lt;/strong&gt; allows Semaphore to download certificates from a private repository configured with Fastlane. We needed to create a deploy key and add it to Semaphore secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
&lt;a href="https://github.com/renderedtext/tech-content/blob/master/ios-semaphore-intro.md#deploy" rel="noopener noreferrer"&gt;&lt;/a&gt;Deploy&lt;/h3&gt;

&lt;p&gt;After you do all your changes, commit it to get the CI/CD workflow started:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git add -A
$ git commit -m "Updates pipeline"
$ git push&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check your Semaphore dashboard and &lt;strong&gt;Voilá&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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67-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%2Fwpblog.semaphoreci.com%2Fwp-content%2Fuploads%2F2020%2F01%2F68747470733a2f2f746563686e6963616c2d636f6e74656e742e73332d73612d656173742d312e616d617a6f6e6177732e636f6d2f73656d6170686f72652d636963642d737563636573732d626c6f636b732e706e67-2.png" alt="Screenshot of the final successful test in Semaphore iOS tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you need to continuously push code to your branches, and App Store Connect processes the build. It becomes available in TestFlight, and you will be able to select it for your new iOS app version.&lt;/p&gt;

&lt;p&gt;Let’s do a quick recap of what we did in this tutorial. Our pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run all unit and UI tests.&lt;/li&gt;
&lt;li&gt;Build the app and generate an &lt;code&gt;ipa&lt;/code&gt; archive.&lt;/li&gt;
&lt;li&gt;Generate automated App Store screenshots.&lt;/li&gt;
&lt;li&gt;Upload the archived &lt;code&gt;ipa&lt;/code&gt; and screenshots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the finished project and explore the code on your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="https://github.com/semaphoreci-demos/semaphore-demo-ios-swift-xcode" rel="noopener noreferrer"&gt;Semaphore Demo iOS Swift Xcode &lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Next steps&lt;/h2&gt;

&lt;p&gt;There is much more that you can do with automated deployments. For example, you can add more steps to your pipeline configuration, such as getting your CHANGELOG file, pushing messages to Slack, automating build number incrementation, dSYM uploads to Crashlytics, and more.&lt;/p&gt;

&lt;p&gt;After you take some time to configure CI/CD for your iOS applications, you can focus on writing code instead of manually delivering your app every time.&lt;/p&gt;

&lt;p&gt;Have questions about this tutorial? Want to show off your results? Reach out to us on Twitter &lt;a href="https://twitter.com/semaphoreci" rel="noopener noreferrer"&gt;@semaphoreci&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>devops</category>
    </item>
    <item>
      <title>iOS 13: The Top 5 Features Your App Needs Now</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Wed, 11 Sep 2019 17:20:00 +0000</pubDate>
      <link>https://forem.com/semaphore/ios-13-the-top-5-features-your-app-needs-now-1n9p</link>
      <guid>https://forem.com/semaphore/ios-13-the-top-5-features-your-app-needs-now-1n9p</guid>
      <description>&lt;p&gt;At &lt;a href="https://semaphoreci.com/blog/ios-developer-community-wwdc"&gt;WWDC 2019&lt;/a&gt;, Apple announced many improvements for iOS 13, such as the much-hyped Dark Mode and increased privacy capabilities. Apple tends to highlight apps in the App Store that implement new features, so now is the time to optimize your apps for the new iOS 13 features.&lt;/p&gt;

&lt;p&gt;Today, I will highlight the five most important features that you, as an iOS developer, should plan to implement.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Dark Mode
&lt;/h2&gt;

&lt;p&gt;Prepare your apps for the Dark Mode feature in iOS 13. Apple is putting so much emphasis on Dark Mode that the WWDC 2019 event environment was totally dark. &lt;/p&gt;

&lt;p&gt;Before this update, you have likely seen apps emulating this capability by creating their own themes using the UIAppearence class. But now that Apple officially supports it, you can prepare for the iOS 13 Dark Mode that is seamlessly integrated throughout the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K2-1XnGj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh3.googleusercontent.com/fzD4ZSO6H9mEE3z3ZhtYZdDt8KycyuvYtpFpqcI7dFSHUfCWQB0-UbKjrpwHBCGi0QhPsRQqcnOFN99sKbsWMNwqvBstXkzmqGIwIHlYMkSWWYit1rt6uRRe9RtQSp0nSUjChI6j" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K2-1XnGj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh3.googleusercontent.com/fzD4ZSO6H9mEE3z3ZhtYZdDt8KycyuvYtpFpqcI7dFSHUfCWQB0-UbKjrpwHBCGi0QhPsRQqcnOFN99sKbsWMNwqvBstXkzmqGIwIHlYMkSWWYit1rt6uRRe9RtQSp0nSUjChI6j" alt="" width="800" height="1345"&gt;&lt;/a&gt;&lt;br&gt;
Screenshot of iOS 13’s Dark Mode functionality (&lt;a href="https://www.apple.com/newsroom/2019/06/apple-previews-ios-13/"&gt;image credit&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/news/?id=0829019a"&gt;As Apple states&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;When a user has Dark Mode turned on, all apps built with the iOS 13 SDK will run in Dark Mode.&lt;/p&gt;

&lt;p&gt;If you need more time to make your apps optimized for Dark Mode, or if Dark Mode is not suited for your app, you can learn how to opt-out.&lt;/p&gt;

&lt;p&gt;However, because the emphasis Apple placed on it at WWDC this year, I recommend adding it to your app’s interface if possible.&lt;/p&gt;
&lt;h3&gt;
  
  
  Dark Mode Best Practices
&lt;/h3&gt;

&lt;p&gt;Choose adaptive colors for your UI by defining custom colors in your asset catalog.&lt;br&gt;
For example, load a color value from an asset catalog by name&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;let&lt;/span&gt; &lt;span class="nv"&gt;labelColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;named&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;customControlColor&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;ul&gt;
&lt;li&gt;&lt;p&gt;The images you create should look good in both light and dark appearances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update custom views with specific methods. One way to do this it is by moving your code to the updateLayer()method so that whenever the UI refreshes, the background color also changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read a complete introduction about implementing Dark Mode for iOS 13 with Apple’s official documentation &lt;a href="https://developer.apple.com/documentation/appkit/supporting_dark_mode_in_your_interface/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Sign in with Apple
&lt;/h2&gt;

&lt;p&gt;In this update, Apple greatly improved its privacy features. Now, users can sign into applications using Apple’s native sign-in feature, like they do with Facebook and Google’s authenticators. The &lt;a href="https://developer.apple.com/sign-in-with-apple/"&gt;Sign In with Apple&lt;/a&gt; feature, introduced in iOS 13, provides fast, easy sign-in without tracking. Users can simply tap a button and use their FaceID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlWES_f2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh6.googleusercontent.com/Aa3w-3rYSKaRi0TzJXRYkeeZz30gtShGLeyKgYDAG4OFmQje6y4u1ljQwfbsmJH70pTWw24rqbb79DWOuwjKwBkG13IEfF5Y2YQxJIHGfhPKaFd2M3pWSt3I03hZCoZp3qa1PTVq" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlWES_f2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh6.googleusercontent.com/Aa3w-3rYSKaRi0TzJXRYkeeZz30gtShGLeyKgYDAG4OFmQje6y4u1ljQwfbsmJH70pTWw24rqbb79DWOuwjKwBkG13IEfF5Y2YQxJIHGfhPKaFd2M3pWSt3I03hZCoZp3qa1PTVq" alt="" width="571" height="960"&gt;&lt;/a&gt;&lt;br&gt;
In iOS 13, users can sign into applications using the secure Sign In with Apple feature (&lt;a href="https://www.apple.com/newsroom/2019/06/apple-previews-ios-13/"&gt;image credit&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The difference from the new Apple authentication option lies in its privacy-conscious features. It keeps users’ data more secure and allows them to keep their activity hidden from advertisers.&lt;/p&gt;

&lt;p&gt;Even better, whenever your app asks for a name and email address, you could choose not to ask. Or, if you prefer, you can allow Apple to create a randomized email address for your users. So, when your app sends a message to the user, it will go to their Apple ID email, so nobody knows their email. &lt;/p&gt;

&lt;p&gt;Whether you should implement this, of course, depends on your business model. If it is possible for your business, though, this feature will communicate to your users that you are being transparent and secure with their data, without the interest to track them and send unsolicited emails or ads.&lt;/p&gt;

&lt;p&gt;The main advantages of Sign In with Apple are that it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hides users’ emails, which may make them more willing to use your app.&lt;/li&gt;
&lt;li&gt;Works everywhere, including browsers, watchOS, tvOS, and more.&lt;/li&gt;
&lt;li&gt;Shows that you respect your users’ privacy and helps strengthen your brand.&lt;/li&gt;
&lt;li&gt;Integrates built-in security without too much effort on your part as the developer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to implement this feature, take a look at the &lt;code&gt;ASAuthorizationAppleIDButton&lt;/code&gt; class to create the Apple Sign in Button. This class allows different visual styles and labels. Then, it captures the results in the authentication request that it returns with data like UserID, Verification Data, Full Name, Verified email, Real User Indicator, Credential State, and more. Also, Password Autofill seemingly integrates with Apple Sign In.&lt;/p&gt;

&lt;p&gt;You can learn more about Apple Sign In &lt;a href="https://developer.apple.com/sign-in-with-apple/get-started/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Siri Shortcuts
&lt;/h2&gt;

&lt;p&gt;If you’ve never integrated Siri into your application, now is the time to evaluate it. Siri’s functionality now offers a better voice experience, additional customization, and more. For example, a food delivery app can allow people to ask about the delivery status of their order, and an event app can remind users to leave on time for a party.&lt;/p&gt;

&lt;p&gt;Depending on your app’s core features, you may find that Siri adds significant value to your user experience.&lt;/p&gt;

&lt;p&gt;Take, for example, conversational shortcuts. Siri can now ask follow-up questions, which makes your app’s voice shortcuts even better. For example, when a user says “Order status,” you can program Siri to ask which order the user is referring to for clarification.&lt;/p&gt;

&lt;p&gt;One possible reason Siri adoption has been low among consumers is that users must navigate to Siri’s settings to record their own custom voice commands. With iOS 13, developers can suggest a voice command within the app and allow users to create it with a tap of a button. This eliminates the need for users to manually record their custom voice commands and makes it easier for them to interact with your app.&lt;/p&gt;

&lt;p&gt;Consider adding a Siri Shortcut button for recurrent tasks in your app, such as placing an order or checking the status of something. Take some time to explore Siri’s updates using the &lt;a href="https://developer.apple.com/documentation/sirikit"&gt;SiriKit documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. SwiftUI
&lt;/h2&gt;

&lt;p&gt;SwiftUI is a user interface toolkit that lets you design apps in a declarative way. This means that you can write code that clearly states what you want it to do. It is natural to write and work seamlessly with the new Xcode design tools, keeping your code and design in synchronization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ggy9TUo---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh6.googleusercontent.com/NpaYXD_TJukRTsBogrYifLUgSg9QVkqvEJXH8lzZFx-00HeItwb-oj-EXJC92emgpDkuFzODf7P6Bjz8e9PVWUXIuVqFLPfYTn4EFErVkGcq1ZIXme8mfTsNHwIS-yjPaFzXGTzZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ggy9TUo---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lh6.googleusercontent.com/NpaYXD_TJukRTsBogrYifLUgSg9QVkqvEJXH8lzZFx-00HeItwb-oj-EXJC92emgpDkuFzODf7P6Bjz8e9PVWUXIuVqFLPfYTn4EFErVkGcq1ZIXme8mfTsNHwIS-yjPaFzXGTzZ" alt="" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Josh Shaffer demonstrating SwiftUI’s interface at WWDC 2019 (&lt;a href="https://www.apple.com/newsroom/2019/06/highlights-from-wwdc-2019/"&gt;image credit&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;One of the things that first impressed me about SwiftUI is how it merges the benefits of Storyboards and code at the same time. For example, the code updates as you drag and drop UI elements into the canvas. This can help in code organization and fix the &lt;a href="https://www.hackingwithswift.com/articles/159/how-to-refactor-massive-view-controllers"&gt;massive view controller problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another advantage is that SwiftUI is a cross-platform, truly native toolkit. It allows your apps to directly access each of Apple’s operating systems with a small amount of code and an interactive design canvas.&lt;/p&gt;

&lt;p&gt;For everything that I previously highlighted with SwiftUI, I recommend only experimenting with it for now rather than quickly putting it into your production codebase. It is the first step from Apple to include these new intuitive design tools that make building interfaces as easy as dragging and dropping. But you should take care to experiment first, decide later!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Core NFC
&lt;/h2&gt;

&lt;p&gt;Core NFC is likely the most difficult feature that I recommend, but it will open up your application’s ability to connect to the physical world.&lt;/p&gt;

&lt;p&gt;Using Core NFC, your app could read Near Field Communication (NFC) tags to give users more information about their physical environment and the real-world objects in it. Imagine the possibilities!&lt;/p&gt;

&lt;p&gt;So, using Core NFC, your app might give users information about products they find in a store or exhibits they visit in a museum.&lt;/p&gt;

&lt;p&gt;Apple improved the use of Core NFC this year by adding the ability to read contactless smartcards, passports, and other government-issued IDs on iPhone 7 devices and up.&lt;/p&gt;

&lt;p&gt;To use Core NFC, you need to enable Xcode capability, use one of the Core NFC sessions objects like &lt;code&gt;NFCTagReaderSession&lt;/code&gt; or &lt;code&gt;NFCNDEFReaderSession&lt;/code&gt; and receive tags in discovery callbacks. Connect to a tag to perform operations, and then invalidate the session.&lt;/p&gt;

&lt;p&gt;This can sound a bit confusing if you have never worked with NFC before. To get started (and inspired by the possibilities), I recommend reading some of &lt;a href="https://developer.apple.com/documentation/corenfc"&gt;Apple’s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Faster, simpler app development for iOS 13
&lt;/h2&gt;

&lt;p&gt;Remember, Apple often highlights applications in the App Store that incorporate the top features and ideas from their latest updates. If you are looking to grow your app’s discoverability and be among the top-ranking apps, this could be your chance. &lt;/p&gt;

&lt;p&gt;If this all sounds overwhelming, automating some parts of your development process can help you focus on development and set repetitive tasks on auto-pilot. &lt;/p&gt;

&lt;p&gt;One way to do this is by using iOS &lt;a href="https://semaphoreci.com/blog/2017/07/27/what-is-the-difference-between-continuous-integration-continuous-deployment-and-continuous-delivery.html"&gt;Continuous Integration and Continuous Delivery&lt;/a&gt; (CI/CD). Semaphore just finished its initiative to support iOS 13, so now you can use our CI/CD platform to compile and test your iOS applications.&lt;/p&gt;

&lt;p&gt;Start with simple things first, and feel free to reach out to the Semaphore team (&lt;a href="https://twitter.com/semaphoreci"&gt;@semaphoreci&lt;/a&gt;) on Twitter if you have any questions!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>iphone</category>
      <category>softwareengineering</category>
      <category>tips</category>
    </item>
    <item>
      <title>Continuous Integration and Continuous Delivery with SemaphoreCI and Fastlane for iOS apps</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Mon, 12 Aug 2019 17:01:14 +0000</pubDate>
      <link>https://forem.com/amarildo/continuous-integration-and-continuous-delivery-with-semaphoreci-and-fastlane-for-ios-apps-2eg3</link>
      <guid>https://forem.com/amarildo/continuous-integration-and-continuous-delivery-with-semaphoreci-and-fastlane-for-ios-apps-2eg3</guid>
      <description>&lt;p&gt;When you develop mobile apps, &lt;strong&gt;you manage the process of the app publication manually&lt;/strong&gt;, using &lt;strong&gt;Xcode Organizer&lt;/strong&gt;, after following some steps like signing, test, build, archive and deploy your build, then change versions and send new builds again and again to the AppStore. &lt;/p&gt;

&lt;p&gt;If you generate your builds daily, &lt;strong&gt;this process is tedious and tiring&lt;/strong&gt;. So, soon or later, you will ask yourself:  &lt;strong&gt;— How could I automate all this proccess?&lt;/strong&gt; The answer to this question becomes essential to your development and deploy flow, it's essential to have a quick feedback loop to iterate when deploying your builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using SemaphoreCI and Fastlane it's a great choice to build products at high velocity&lt;/strong&gt;. Whenever you push your code to your remote repository, SemaphoreCI will automatically run your custom build, test and deploy pipeline.&lt;/p&gt;

&lt;p&gt;So, let’s start playing with some configuration and set up our first continuous integration flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the project
&lt;/h2&gt;

&lt;p&gt;The steps that we will follow in this tutorial to use our Continuous Integration pipeline is going to look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Clone SemaphoreCI Swift demo project from Github&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Configuring SemaphoreCI pipeline&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Understanding the configuration of the files in our project&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;Push our first build with Continuous Integration&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Clone SemaphoreCI Swift demo project from Github
&lt;/h2&gt;

&lt;p&gt;In order to continue with this tutorial, you should grab a copy of the SemaphoreCI demo project from GitHub and &lt;strong&gt;clone it to your computer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will use along the tutorial the following tools:&lt;br&gt;
&lt;strong&gt;1. Git&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2. Xcode&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;3. Fastlane&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;4. SemaphoreCI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:semaphoreci-demos/semaphore-demo-ios-swift-xcode.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I recommend to you, to &lt;strong&gt;fork the project&lt;/strong&gt; and clone from your forked repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring SemaphoreCI pipeline
&lt;/h2&gt;

&lt;p&gt;Go to your SemaphoreCI dashboard and &lt;strong&gt;create a new project&lt;/strong&gt;. Select a repository &lt;code&gt;semaphore-demo-ios-swift-xcode&lt;/code&gt;and connect to SemaphoreCI. &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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B09.42.26.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B09.42.26.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this moment, you will see an empty connected project.  This is because we didn’t push anything to the project yet.&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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B11.18.34.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B11.18.34.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On your cloned project, open &lt;code&gt;.semaphore/semaphore.yml&lt;/code&gt; file. This is the configuration file to run your pipeline every time that you push your code. The file is well commented and you need to change it according to your own necessities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.semaphore/semaphore.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Use the latest stable version of Semaphore 2.0 YML syntax:
version: v1.0

# Name your pipeline. In case you connect multiple pipelines with promotions,
# the name will help you differentiate between, for example, a CI build phase
# and delivery phases.
name: Semaphore iOS Swift example with Fastlane

# An agent defines the environment in which your code runs.
# It is a combination of one of available machine types and operating
# system images.
# See https://docs.semaphoreci.com/article/20-machine-types
# and https://docs.semaphoreci.com/article/120-macos-mojave-image
agent:
  machine:
    type: a1-standard-4
    os_image: macos-mojave

# Blocks are the heart of a pipeline and are executed sequentially.
# Each block has a task that defines one or more jobs. Jobs define the
# commands to execute.
# See https://docs.semaphoreci.com/article/62-concepts
blocks:
  - name: Run tests
    task:
      # Set environment variables that your project requires.
      # See https://docs.semaphoreci.com/article/66-environment-variables-and-secrets
      env_vars:
        - name: LANG
          value: en_US.UTF-8
      prologue:
        commands:
          # Download source code from GitHub:
          - checkout

          # Restore dependencies from cache. This command will not fail in
          # case of a cache miss. In case of a cache hit, bundle  install will
          # complete in about a second.
          # For more info on caching, see https://docs.semaphoreci.com/article/68-caching-dependencies
          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH-,gems-master-
          - bundle install --path vendor/bundle
          - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) vendor/bundle
      jobs:
        - name: Fastlane test
          commands:
            # Select an Xcode version, for available versions
            # See https://docs.semaphoreci.com/article/120-macos-mojave-image
            - bundle exec xcversion select 10.3
            # Run tests of iOS and Mac app on a simulator or connected device
            # See https://docs.fastlane.tools/actions/scan/
            - bundle exec fastlane test

  - name: Build app
    task:
      env_vars:
        - name: LANG
          value: en_US.UTF-8
      prologue:
        commands:
          - checkout
          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH-,gems-master-
          - bundle install --path vendor/bundle
          - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) vendor/bundle
      jobs:
        - name: Fastlane build
          commands:
            - bundle exec xcversion select 10.3
            # Gym builds and packages iOS apps.
            # See https://docs.fastlane.tools/actions/build_app/
            - bundle exec fastlane release

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

&lt;/div&gt;



&lt;p&gt;If you try to push your code at this moment, your pipeline wouldn’t work yet and will fail. You need to &lt;strong&gt;configure your keys and secrets&lt;/strong&gt; to allow SemaphoreCI to integrate with your project. &lt;/p&gt;

&lt;p&gt;To add a deploy key to your Semaphore project you will need to create secrets to add to your pipeline configuration file. So, let's store the deploy key as a secret file in the SemaphoreCI environment.&lt;/p&gt;

&lt;p&gt;If you have not installed the sem command-line tool that we are using in this tutorial, this is a good time to install it, see the &lt;a href="https://docs.semaphoreci.com/article/53-sem-reference" rel="noopener noreferrer"&gt;sem reference&lt;/a&gt; and follow the instructions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sem create secret your-fastlane-ios-certificates-repo -f id_rsa_semaphoreci:/Users/semaphore/.keys/your-fastlane-ios-certificates-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the following message on the terminal, &lt;code&gt;Secret ‘fastlane-ios-certificates-repo’ created.&lt;/code&gt;. This means that everything worked as expected.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;id_rsa_semaphoreci&lt;/code&gt; it's your ssh file for SemaphoreCI. Upload it to GitHub so you can deploy your code without further problems. &lt;/p&gt;

&lt;p&gt;In our case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-keygen -t rsa -f id_rsa_semaphoreci
cd ~/.ssh/id_rsa_semaphoreci.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Copy and paste to Github SSH keys configuration.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, &lt;strong&gt;add the URL for the certificates repository and the encryption password as environment variables&lt;/strong&gt; that will be accessible in SemaphoreCI. I recommend also adding the App Store developer account’s credentials to the same secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sem create secret fastlane-env \
  -e MATCH_GIT_URL=“&amp;lt;your ssh git url&amp;gt;” \
  -e MATCH_PASSWORD=“&amp;lt;password for decryption&amp;gt;” \
  -e FASTLANE_USER=“&amp;lt;App Store developer’s Apple ID&amp;gt;” \
  -e FASTLANE_PASSWORD=“&amp;lt;App Store developer’s password&amp;gt;”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After run this command, you will find your keys in configuration secrets inside SemaphoreCI dashboard.&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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B10.37.36.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B10.37.36.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Updates your &lt;code&gt;.semaphore/semaphore.yml&lt;/code&gt; file with your keys and secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
        - name: Fastlane build
        commands:
            - chmod 0600 ~/.keys/*
            - ssh-add ~/.keys/*
            - bundle exec fastlane release
secrets:
        - name: fastlane-env
        - name: fastlane-ios-certificates-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding the Fastlane Configuration
&lt;/h2&gt;

&lt;p&gt;When you open the demo project folder, you will see that you have a fastlane folder with some files inside. This folder was added after we installed and run fastlane for the first time. To understand more about the process of fastlane installation and configuration you should read this &lt;a href="https://docs.fastlane.tools/getting-started/ios/setup/" rel="noopener noreferrer"&gt;introductory article&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let's go with the steps that usually you will take.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Install fastlane&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2. Configure fastlane files&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;3. Test if everything is working&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As fastlane describes in their own website:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fastlane is the easiest way to automate beta deployments and releases for your iOS apps. It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It also supports other platforms.&lt;/p&gt;

&lt;p&gt;Install the latest Xcode command line tools if you haven’t installed yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select —install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install fastlane.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Using RubyGems
sudo gem install fastlane -NV

# Alternatively using Homebrew
brew cask install fastlane
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After Fastlane installation, run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastlane init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fastlane will automatically detect your project&lt;/strong&gt; and ask for any missing information. In our case, these folders and files installed by fastlane exists as we downloaded from the demo project in Github. Depending on what kind of setup you choose, different files will be set up for you out of the box.&lt;/p&gt;

&lt;p&gt;The most interesting file is &lt;code&gt;fastlane/Fastfile&lt;/code&gt;, which contains all the information that is needed to distribute your app.&lt;/p&gt;

&lt;p&gt;Our fastlane current folder. Again, the files are well commented, so I will not give further explanations about each of them.&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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B09.34.37.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B09.34.37.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fastlane/Appfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For more information about the Appfile, see:
#     https://docs.fastlane.tools/advanced/#appfile

app_identifier "***" # The bundle identifier of your app
apple_id "***" # Your Apple email address
team_id "***" # Developer Portal Team ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;fastlane/Fastfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do

  before_all do
    # installed via the semaphore plugin with `fastlane add_plugin semaphore`
    setup_semaphore
  end

  desc "Run Tests"
  lane :test do
    scan
  end

  desc "Deploy a new version to the App Store"
  lane :release do
    match(type: "appstore")
    gym(export_method: "app-store") # Build your app - more options available
    deliver(force: true)
  end
end

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;fastlane/Gymfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For more information about this configuration visit
# https://github.com/fastlane/fastlane/tree/master/gym#gymfile
#
# In general, you can use the options available
# fastlane gym --help

# Remove the # in front of the line to enable the option

scheme "HelloWorld"

sdk "iphoneos12.4"

output_directory "./"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;fastlane/Matchfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git_url("https://github.com/amarildolucas/fastlane_certficates")

storage_mode("git")

type("appstore") # The default type, can be: appstore, adhoc, enterprise or development

# app_identifier(["com.amarildolucas.com"])
# username("***") # Your Apple Developer Portal username

# For all available options run `fastlane match --help`
# Remove the # in the beginning of the line to enable the other options

# The docs are available on https://docs.fastlane.tools/actions/match
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;fastlane/Pluginfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!

gem 'fastlane-plugin-semaphore'

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

&lt;/div&gt;



&lt;p&gt;This is everything we need to set up and deploy our first build with continuous integration. The code is very specific and self-explanatory. You just defined 2 different lanes, one for your test deployment, one for App Store release. To release your app in the App Store, all you have to do now is push your code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ensure that Xcode "automatically manage signing" is unchecked in Xcode. And that your Signing (Release) contains the match AppStore provisioning profile selected. &lt;/p&gt;

&lt;h2&gt;
  
  
  Some considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gemfile
&lt;/h3&gt;

&lt;p&gt;It is recommended that you use a Gemfile to define your dependency on fastlane. This will clearly define the used fastlane version, and its dependencies, and will also speed up using fastlane.&lt;/p&gt;

&lt;p&gt;Our current Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source 'https://rubygems.org'

gem "fastlane"
gem "xcode-install"
gem "cocoapods"

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up Fastlane Match
&lt;/h3&gt;

&lt;p&gt;You can use fastlane match to manage code signing. We use it in our fastlane setup.&lt;/p&gt;

&lt;p&gt;To set up the match, you’ll need a private Git repository. Follow the  &lt;a href="https://docs.fastlane.tools/actions/match/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and run the init command from the root directory of our project and follow the instructions shown in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec fastlane match init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our case, our Matchfile exists from the cloned demo project in Github. So, run &lt;code&gt;fastlane match&lt;/code&gt;  without init to get all required keys, certificates and provisioning profiles installed to your project. 🙌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Private information like API keys or deploy credentials shouldn’t be written in the pipeline definition file or elsewhere committed to source control. On Semaphore you define these values as &lt;em&gt;secrets&lt;/em&gt; using either the sem CLI or through the web interface (Configuration part of the sidebar -&amp;gt; Secrets). Secrets are shared by all projects in the organization. &lt;strong&gt;— Semaphore Team&lt;/strong&gt;  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build your project and run fastlane to check if everything that we did it until now is working as expected.&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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B10.26.41.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B10.26.41.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see the message &lt;code&gt;[10:28:38]: fastlane.tools finished successfully 🎉&lt;/code&gt;, celebrate 🎉.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, we just need to push our code to GitHub, and SemaphoreCI will run the CI/CD pipeline for us.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add -A
git commit -m "setup semaphore"
git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you push your code to master branch in GitHub, your semaphore pipeline will run for the first time. If you click in the commit link, you can see all the processes (steps) in a beautiful layout components separated the steps of your pipeline configuration.&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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B11.58.59.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%2Famarildolucas.s3-sa-east-1.amazonaws.com%2FSemaphoreCI%2FCaptura%2Bde%2BTela%2B2019-08-12%2B%25C3%25A0s%2B11.58.59.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voilá! Now you just need to continuously push code to your branches and App Store Connect processes the build, and it becomes available in TestFlight and you will be able to select it for your new iOS app version.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There is much more that you can do with automated deployments. CI/CD pipeline has a lot of advantages, more than from the steps we follow through this tutorial. You can add more steps to your pipeline configuration, like get your CHANGELOG file, push messages to Slack, automate build number incrementation, dSYM uploads to Crashlytics, etc. &lt;/p&gt;

&lt;p&gt;After you take some time configuring, all this stuff will help you stay focused on writing code rather to manually deliver your app every time. So, your build updates are not stressful and tedious. You can inspect your code by adding tools in the process, for example to run static code reviews, linting, tests or any other important step that you could automate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However, start with simple things first.&lt;/strong&gt; If you've made it this far, congrats! 😃 I hope you found this post helpful. &lt;/p&gt;

&lt;p&gt;Want to deliver continuously your iOS applications? Check out&lt;a href="https://semaphoreci.com/product/ios" rel="noopener noreferrer"&gt;Build, test and deliver your iOS apps with Semaphore CI/CD&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>swiftcicd</category>
      <category>semaphoreci</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Automatic Reference Counting (ARC) in class instances</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Sun, 07 Apr 2019 23:00:49 +0000</pubDate>
      <link>https://forem.com/amarildo/automatic-reference-counting-arc-in-class-instances-13a9</link>
      <guid>https://forem.com/amarildo/automatic-reference-counting-arc-in-class-instances-13a9</guid>
      <description>&lt;h2&gt;
  
  
  An introduction to ARC
&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmtohx0ju0k471p4myywx.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmtohx0ju0k471p4myywx.png" alt="Automatic Reference Counting Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://developer.apple.com/swift/" rel="noopener noreferrer"&gt;Swift language&lt;/a&gt; memory management works out of the box and you don't need even to think about it yourself.&lt;/p&gt;

&lt;p&gt;In this article i'll share the basic about ARC. ARC just works! It's frees up the memory used by your class instances when their no longer needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By Apple words:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about instance. Addictionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes insted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's practice!!!
&lt;/h2&gt;

&lt;p&gt;Let's see how this works with our previous music app idea example.&lt;/p&gt;

&lt;p&gt;You have a &lt;code&gt;class&lt;/code&gt; called &lt;code&gt;Artist&lt;/code&gt;. We will play a little bit with code now.&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;class&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&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;name&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;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;deinit&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being deinitialized"&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;We will now create an &lt;code&gt;Artist&lt;/code&gt; instance and assign it to some variables.&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;var&lt;/span&gt; &lt;span class="nv"&gt;artist1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;artist2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;artist3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

&lt;span class="n"&gt;artist1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;"Taylor Swift"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;artist2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;artist1&lt;/span&gt;
&lt;span class="n"&gt;artist3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;artist1&lt;/span&gt;

&lt;span class="n"&gt;artist1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="n"&gt;artist2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the instance in &lt;code&gt;artist3&lt;/code&gt; it wasn't &lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;Artist&lt;/code&gt; instance it's never deallocated. You can check this by seeing the number of &lt;code&gt;"Artist \(name) is being deinitialized"&lt;/code&gt; printed in the result in your console. And this happens because there is now a strong reference from &lt;code&gt;artist1&lt;/code&gt; to the new &lt;code&gt;Artist&lt;/code&gt; instances. The third &lt;code&gt;strong reference&lt;/code&gt; never was deallocated and so, the instance it's broken. So you need to change the line to &lt;code&gt;artist3 = nil&lt;/code&gt; in order to fix the last strong reference.&lt;/p&gt;

&lt;p&gt;Now lets learn about new references than &lt;code&gt;strong&lt;/code&gt;, &lt;code&gt;weak&lt;/code&gt; and &lt;code&gt;unowned&lt;/code&gt;, by understanding how it's possible sometimes to have instance of a class that never gets to the point where it has zero &lt;code&gt;strong references&lt;/code&gt; and this is known as &lt;code&gt;strong reference cycle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is where we defined some of our relationships between &lt;code&gt;class&lt;/code&gt;es as &lt;code&gt;weak&lt;/code&gt; or &lt;code&gt;unowned&lt;/code&gt; insted of &lt;code&gt;strong references&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical example about weak.
&lt;/h2&gt;

&lt;p&gt;We have one &lt;code&gt;class&lt;/code&gt; called &lt;code&gt;Artist&lt;/code&gt; and other called &lt;code&gt;Label&lt;/code&gt;.&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;class&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Label&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="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="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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;deinit&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being deinitialized"&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;The second &lt;code&gt;class&lt;/code&gt; called &lt;code&gt;Label&lt;/code&gt;.&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;class&lt;/span&gt; &lt;span class="kt"&gt;Label&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;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;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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="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="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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;"Label &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;deinit&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;"Label &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being deinitialized"&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 play with some &lt;code&gt;initialization&lt;/code&gt;. Below is the result!&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;var&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

&lt;span class="n"&gt;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;"Taylor Swift"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Label&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;"Sonic Music"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;artist&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;label&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;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;artist&lt;/span&gt;

&lt;span class="n"&gt;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, when we pass nil to both variables, the &lt;code&gt;strong reference&lt;/code&gt; not drop to zero and the instance it's not deallocated. Neither &lt;code&gt;deinitializer&lt;/code&gt; was called and nothing it's printed in console. This can cause memory leak and other problems to your apps. I see this happening a lot while people work with instances of &lt;code&gt;UITableView&lt;/code&gt; delegate methods or when try to capture values inside &lt;code&gt;Clocure&lt;/code&gt;s. We will expand more about these topics in future articles.&lt;/p&gt;

&lt;p&gt;So, how we break this?&lt;/p&gt;

&lt;h2&gt;
  
  
  weak weak weak!
&lt;/h2&gt;

&lt;p&gt;In this case because we can have an &lt;code&gt;Artist&lt;/code&gt; without a &lt;code&gt;Label&lt;/code&gt; or &lt;code&gt;Label&lt;/code&gt; without an &lt;code&gt;Artist&lt;/code&gt;, it's possible to use &lt;code&gt;weak&lt;/code&gt;reference. Because the lifetime of &lt;code&gt;Label&lt;/code&gt; can finish first than the &lt;code&gt;Artist&lt;/code&gt; in this context, we use &lt;code&gt;weak references&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We use &lt;code&gt;weak references&lt;/code&gt; when the other instance has a shorter lifetime, this mean, when the other instance can be deallocated first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the previous example we just need to change our class by adding the &lt;code&gt;weak reference&lt;/code&gt; before the &lt;code&gt;Artist&lt;/code&gt; declaration.&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;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Artist&lt;/code&gt; instance still has a &lt;code&gt;strong reference&lt;/code&gt; to the &lt;code&gt;Label&lt;/code&gt; instance, but the &lt;code&gt;Label&lt;/code&gt; instance has now a &lt;code&gt;weak reference&lt;/code&gt; to the &lt;code&gt;Artist&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Now, if in our test we add &lt;code&gt;artist = nil&lt;/code&gt;, we will see a different result in console and instances being deallocated. &lt;strong&gt;Try yourself a litle bit!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So when to use the &lt;code&gt;unowned reference&lt;/code&gt; then?!
&lt;/h2&gt;

&lt;p&gt;We use it when the other instance has the same lifetime or longer lifetime.&lt;/p&gt;

&lt;p&gt;In the below quick example, you can see two &lt;code&gt;class&lt;/code&gt;es and understand their relationship. An &lt;code&gt;Artist&lt;/code&gt; can have zero or more &lt;code&gt;Album&lt;/code&gt;s but an &lt;code&gt;Album&lt;/code&gt; can't exists without an &lt;code&gt;Artist&lt;/code&gt;.&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;class&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;album&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Album&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="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="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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;deinit&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;"Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being deinitialized"&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;div class="highlight js-code-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;Album&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;title&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;unowned&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;title&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;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&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;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;artist&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;"Album &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;, Artist &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;artist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being initialized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;deinit&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;"Album &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; is being deinitialized"&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 is a great scenario to use the &lt;code&gt;unowned reference&lt;/code&gt;. Because an &lt;code&gt;Album&lt;/code&gt; will always have an &lt;code&gt;Artist&lt;/code&gt;, we use the &lt;code&gt;unowned reference&lt;/code&gt; to avoid &lt;code&gt;strong reference cycle&lt;/code&gt; in the defined property. You can just update the &lt;code&gt;Album&lt;/code&gt; class with&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;unowned&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See some results and please try different inputs to test diferrent outputs to better understanding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always check wether the &lt;code&gt;deinitializer&lt;/code&gt; was called or not.&lt;/strong&gt;&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;var&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;album&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Album&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

&lt;span class="n"&gt;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Artist&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;"Taylor Swift"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;artist&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;album&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Album&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Fearless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;artist&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;artist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;While there is a lot to find on the internet about ARC, I mainly used the Apple Swift Book and it is very clear and complete.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.swift.org/swift-book/" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;I hope you enjoyed the post and if so, please follow me because more content will come soon. I'll write more about memory management in the next articles.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also consider following me on &lt;strong&gt;&lt;a href="http://twitter.com/amarildulucas" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/strong&gt;? 😬 &lt;strong&gt;@amarildulucas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Please, english isn't my native language, so feel free to send me any feedback about typos or anything.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
    <item>
      <title>Swift For-In Loops</title>
      <dc:creator>Amarildo Lucas</dc:creator>
      <pubDate>Fri, 05 Apr 2019 20:08:14 +0000</pubDate>
      <link>https://forem.com/amarildo/for-in-loops-3non</link>
      <guid>https://forem.com/amarildo/for-in-loops-3non</guid>
      <description>&lt;p&gt;In &lt;a href="https://developer.apple.com/swift/"&gt;Swift language&lt;/a&gt; we use the &lt;code&gt;for-in&lt;/code&gt; loop to iterate over a sequence. A sequence contains items such &lt;code&gt;Array&lt;/code&gt; elements, &lt;code&gt;Range&lt;/code&gt;s of numbers or &lt;code&gt;Character&lt;/code&gt;s in a &lt;code&gt;String&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;Let's quickly experiment with some code. You can iterate a genres of music &lt;code&gt;Array&lt;/code&gt; like this for example:&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;// Iterate genres&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;genres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Ambient"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Dubstep"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Electronic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hip Hop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Jazz"&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;"Choose a genre:"&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;genre&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;genres&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;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;genre&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, we iterated over an &lt;code&gt;Array&lt;/code&gt; printing every genre inside. We can go further and try the same using a &lt;code&gt;Dictionary&lt;/code&gt; insted of an &lt;code&gt;Array&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we have music titles with a file type.&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;// Iterate dictionaries&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;titleWithAudioTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Castle in the Hill"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MP3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Different seas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"WAV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"See you again"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FLAC"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audioType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;titleWithAudioTypes&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;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="se"&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;audioType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lowercased&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above, each item in the &lt;code&gt;Dictionary&lt;/code&gt; is returned as &lt;strong&gt;(key, value)&lt;/strong&gt; pairs.&lt;/p&gt;

&lt;p&gt;Now let's say that we want to put a sound to repeat five times. You could use &lt;code&gt;for-in&lt;/code&gt; loops with numeric &lt;code&gt;Range&lt;/code&gt;s to achieve this.&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;// Iterate ranges&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;soundTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"See you again.mp3"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;soundRepeats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;time&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="n"&gt;soundRepeats&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;"Repeating &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;soundTitle&lt;/span&gt;&lt;span class="se"&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;time&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; time(s)"&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;The key here is the closed &lt;code&gt;Range&lt;/code&gt; operator &lt;code&gt;(...)&lt;/code&gt;. Most of the times when you don't need the constant inside the loop, for example time in &lt;code&gt;for time in (...)&lt;/code&gt; you can ignore the values by using an underscore &lt;code&gt;_&lt;/code&gt; in place of a variable name. &lt;code&gt;time&lt;/code&gt; it's implicity declared by its inclusion in the loop declaration.&lt;/p&gt;

&lt;p&gt;You can read more about &lt;code&gt;for-in&lt;/code&gt; loops in Swift on &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html"&gt;Apple Swift Book&lt;/a&gt;.&lt;/p&gt;

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