<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ SwiftUI - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ SwiftUI - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 26 Aug 2026 17:06:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/swiftui/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Learn SwiftUI and Create an iOS App From Scratch ]]>
                </title>
                <description>
                    <![CDATA[ Learn how to create a complete iOS app from scratch using SwiftUI and Xcode. We just posted a course on the freeCodeCamp.org YouTube channel that will teach you to build a feature-rich movie and TV browsing app with a dynamic home screen, powerful se... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-swiftui-and-create-an-ios-app-from-scratch/</link>
                <guid isPermaLink="false">68f7d59ad8e7070995147d16</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 21 Oct 2025 18:48:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761072521870/418af7e2-c265-4088-8432-19dad9d1b194.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Learn how to create a complete iOS app from scratch using SwiftUI and Xcode.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will teach you to build a feature-rich movie and TV browsing app with a dynamic home screen, powerful search, and detail screens that play YouTube trailers.</p>
<p>You will also implement a download manager to save titles for offline viewing using SwiftData. By integrating The Movie Database and YouTube APIs, this project provides excellent hands-on practice with SwiftUI, API integration, and modern data storage. Carlos Valentin created this course.</p>
<p>Here are the sections in this course:</p>
<ul>
<li><p>Essentials</p>
</li>
<li><p>Networking</p>
</li>
<li><p>API Networking Requests</p>
</li>
<li><p>Navigation</p>
</li>
<li><p>Search</p>
</li>
<li><p>SwiftData</p>
</li>
</ul>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/-VC3hIEL7eQ">the freeCodeCamp.org YouTube channel</a> (4-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/-VC3hIEL7eQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Robust Networking Layers in Swift with OpenAPI ]]>
                </title>
                <description>
                    <![CDATA[ What is the Problem We’re Solving? For many app developers, including me, writing the networking layer of an application is a familiar and tedious process. You write and test your first call and after that, it involves a repetitive cycle of tasks. Th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-robust-networking-layers-in-swift-with-openapi/</link>
                <guid isPermaLink="false">687fd1a603524e3b4e7b77fe</guid>
                
                    <category>
                        <![CDATA[ OpenApi ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ openapi generator ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OpenAPI Specification ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sravan Karuturi ]]>
                </dc:creator>
                <pubDate>Tue, 22 Jul 2025 18:00:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753206547489/dce9a849-1ccd-4cb0-bca8-f879a5aadf5f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-what-is-the-problem-were-solving"><strong>What is the Problem We’re Solving?</strong></h2>
<p>For many app developers, including me, writing the networking layer of an application is a familiar and tedious process. You write and test your first call and after that, it involves a repetitive cycle of tasks.</p>
<p>This is how it would look in the case of Swift:</p>
<ol>
<li><p>You create a <code>URLSession</code> Instance.</p>
</li>
<li><p>You create a <code>URLRequest</code> Object.</p>
</li>
<li><p>You create the <code>@Codable</code> models to match the expected input and output from the server.</p>
</li>
</ol>
<p>You do the above steps for each API endpoint you have on your backend that your app uses. Not only is this process time-consuming and not challenging for developers, it’s also error prone. </p>
<p>In the above case, if there was a minor change in the backend API – perhaps a renamed field or a new property – this would lead to the app potentially breaking. But you wouldn’t know this until you shipped it to QA or in a worse case, your consumer. This is where the OpenAPI Specification emerges as a modern, robust solution. </p>
<p>In this tutorial, you’ll learn what OpenAPI is and how it can help make your development process better. After that, we’ll implement OpenAPI by creating a small SwiftUI app and using OpenAPI methodologies to interface with the <code>JSONPlaceholder</code> API. Let’s get started.</p>
<h2 id="heading-who-is-this-guide-for"><strong>Who is This Guide For?</strong></h2>
<p>This guide is intended both for new developers looking for best practices and for experienced developers looking to implement or learn more about the OpenAPI Specification. Let’s get into it.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-openapi-and-why-should-you-care">What is OpenAPI and Why Should You Care?</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-benefits-for-swift-ios-developers">Benefits for Swift (iOS) Developers</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-a-practical-guide-to-implementing-this-solution">A Practical Guide to Implementing This Solution</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-create-a-good-openapiyaml-file-the-specification">Step 1: Create a good openapi.yaml file (the specification)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-set-up-your-project">Step 2: Set up your project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-write-a-wrapper">Step 3: Write a wrapper</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-call-the-wrapper-and-display-the-data">Step 4: Call the wrapper and display the data</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-potential-pitfalls">Potential Pitfalls</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-verbose-or-ugly-generated-code">Verbose or ugly generated code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-large-specs-and-performance-issues">Large Specs and Performance Issues</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-unsupported-spec-features">Unsupported Spec Features</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion-embrace-spec-driven-development">Conclusion: Embrace Spec-Driven Development</a></p>
</li>
</ul>
<h2 id="heading-what-is-openapi-and-why-should-you-care"><strong>What is OpenAPI and Why Should You Care?</strong></h2>
<p>At its core, the OpenAPI Specification provides a <em>standard, language-agnostic interface</em> for describing RESTful APIs. This specification, once populated, allows both humans and computers to discover and understand the capabilities of a service without needing to access the source code or the network requests.</p>
<p>The power of OpenAPI is that it acts as a <em>formal contract between different parts of the system.</em> This contract helps both frontend and backend programmers by removing ambiguity during design process. This also has added benefit of using code generators to generate boiler-plate code both on backend and on the client ( which we will also discuss today ).</p>
<p>Traditionally when you want to create a new API in a team, either the PM, the frontend engineer, or the backend engineer takes it upon themselves to request it. Then the backend team builds it and documents it. This in turn is used by the front end team to use the API. </p>
<p><code>Some Requester → Backend Team → Documentation → Frontend Team</code></p>
<p>If you’re using OpenAPI, when someone makes a request for a new API, it is formalized into a specification after deliberations with both the frontend and the backend team. This then serves as the source of truth and is used to generate the backend and the frontend code without as much interdependence.</p>
<p><code>Some Requester → All Teams → Specification → All Teams.</code></p>
<p>This not only streamlines the process of adding new APIs, but provides a definitive source of truth for each endpoint. This also makes it so that frontend engineers and backend engineers are not misaligned about a provided parameter in the result being an <code>Int</code> or a <code>String</code> and so on. <strong>It’s all in the Spec.</strong></p>
<h3 id="heading-benefits-for-swift-ios-developers"><strong>Benefits for Swift (iOS) Developers</strong></h3>
<p>Adopting OpenAPI and <code>swift-openapi-generator</code> brings a host of tangible benefits to the Swift/App development process. It transforms how applications interact with web services in a few key ways.</p>
<h4 id="heading-reduced-development-time-and-cost">Reduced Development Time and Cost</h4>
<p>The most immediate improvement you will see is the significant reduction in boilerplate code you have to write. The generator automates the creation of what is called boilerplate code or ceremonial code. This is the repetitive logic for network requests, response handling, and data model definitions.</p>
<p>By delegating this work, developers can work on the core features of the application which leads to faster and more interesting development cycles.</p>
<h4 id="heading-compile-time-type-safety">Compile Time Type Safety</h4>
<p>This has been a major improvement for me personally. Instead of relying on the “strongly” typed keys for JSON parsing, we now work with strongly typed models. The generator creates native Swift struct and enum types directly from the schemas defined in the OpenAPI document. This brings the power of a strongly-typed system to the networking and parsing layer.</p>
<p>For example, if the return value of an API is made optional, instead of crashing at runtime, we will fail to compile at build time. This forces us to address this issue right away. </p>
<h4 id="heading-improved-collaboration-and-interoperability">Improved Collaboration and Interoperability</h4>
<p>This makes sure that all the developers are on the same page with regard to a given endpoint. And since this specification is language agnostic, it will serve as a universal language for all teams involved in the project – mobile, web and backend. </p>
<h4 id="heading-other-tooling">Other Tooling</h4>
<p>Once you have a specification, you can use that to power a wide variety of tools. You can generate interactive documentation, create mock servers for frontend development, and run automated tests. </p>
<p>Alright hopefully you’re sold – so now how do you implement this into your project?</p>
<h2 id="heading-a-practical-guide-to-implementing-this-solution">A Practical Guide to Implementing This Solution</h2>
<p>We’ll now take a look at a practical example so you can understand how you can implement this in a project. This involves:</p>
<ul>
<li><p>Creating an openapi.yaml file to describe the API specification.</p>
</li>
<li><p>Configuring and integrating <code>swift-openapi-generator</code> into a SwiftUI application. </p>
</li>
<li><p>Prototyping an app that fetches and displays a list of posts from the <a target="_blank" href="https://jsonplaceholder.typicode.com/">https://jsonplaceholder.typicode.com/</a> </p>
</li>
</ul>
<p>To follow along, you will need Xcode installed and a basic understanding of Swift programming and SwiftUI for App development.</p>
<h3 id="heading-step-1-create-a-good-openapiyaml-file-the-specification">Step 1: Create a good openapi.yaml file (the specification)</h3>
<p>The quality of a specification is really important because it directly determines the quality of the code produced by <code>swift-openapi-generator</code>. If you don’t have a good specification, you might run into several issues that developers often complain about, like confusing and long method names.</p>
<p>For example, it might generate something like <code>get_all_my_meal_recipes_hyphen_detailed</code>. This might happen because the generator is forced to create a new name based on the API path if the identifier is not provided in the spec. So, instead of dealing with these issues one after the other, we will create a <em>good clear specification</em> to start with.</p>
<p>Since we’re using the <code>jsonplaceholder</code> as our backend server, we are limited by what tweaks we can make – but it is a fantastic project that lets us mimic a backend server.</p>
<p>In general, an OpenAPI.yaml file contains:</p>
<ol>
<li><p>OpenAPI Info and servers – This will provide the metadata about the API like the OpenAPI version, which server to point to for calls, and so on. </p>
</li>
<li><p>Paths – This will provide the available endpoints. In our case, it can contain /posts as one of them. We also will have to mention the kind of endpoint (get, post, put, and so on)</p>
</li>
<li><p>OperationID – This field instructs the generator to create a clear method with this name. </p>
</li>
<li><p>Responses – This defines the possible outcomes of an API call. We will specify the structure of a successful 200 OK response or any other errors here. </p>
</li>
<li><p>Components / Schemas – This defines all the reusable components and data models. If we have a Post schema definer here, the generator will use this to create a Post struct in Swift to match this. </p>
</li>
</ol>
<p>Keeping in mind all these elements, I compiled a yaml file for us to use for this tutorial:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># openapi.yaml</span>
<span class="hljs-attr">openapi:</span> <span class="hljs-string">"3.0.3"</span>
<span class="hljs-attr">info:</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">"JSONPlaceholder API"</span>
  <span class="hljs-attr">version:</span> <span class="hljs-string">"1.0.0"</span>
<span class="hljs-attr">servers:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/posts:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">"Get all posts"</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">"getPosts"</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">"200":</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"A list of posts"</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">array</span>
                <span class="hljs-attr">items:</span>
                  <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/Post"</span>
<span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">Post:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">required:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">userId</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">id</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">title</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">body</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">userId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
        <span class="hljs-attr">id:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
        <span class="hljs-attr">title:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
        <span class="hljs-attr">body:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
</code></pre>
<p>The first line here, <code>openapi: “3.0.3”</code>, just tells the generators and parsers that we are using version <code>3.0.3</code>. </p>
<p>Next, we have some more metadata – the name and version of the API. We also have the server we are calling with our APIs.</p>
<p>After defining this metadata, we now define our endpoints. For the sake of this example, let’s assume that we only have one endpoint to call to get posts. We represent this by saying <code>/posts</code> under paths. We then specify which kind it is by specifying <code>get:</code>.</p>
<p>We give a short description of what it does in the <code>summary</code> and then specify an <code>operationId</code> which is what we this function will be called in our generated code. We also specify exactly what structure the response will have, that is, a JSON of an array of <code>Posts</code>.</p>
<p>We then list any components we have across our APIs like the <code>Post</code>. Note that we are using the <code>Post</code> schema in the return response structure before we define it further down. The schemas in components will determine the Model structs we will generate using this yaml file.</p>
<h3 id="heading-step-2-set-up-your-project">Step 2: Set up your project</h3>
<p>Create a new SwiftUI project. For the purpose of this tutorial, we’ll use an iOS app – but you can do this with any app. Select Swift as the language and SwiftUI for the interface.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047209636/75cad7d3-f403-4285-8209-fd2bb65418e5.png" alt="App Creation Screen" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047246793/3491aa5d-c35c-4157-adf2-789fe5e9cd96.png" alt="Basic SwiftUI App after it's created" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>Add the <code>openapi.yaml</code> file we just created to this project. (You can also create this file in Xcode and copy, paste from the script above.)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047290178/fc31b759-b1c4-4b48-b58b-d90109614cd0.png" alt="Adding the openapi.yaml file to our project" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>Now, add the following swift packages to the project. (<strong>Note: Please read the entire section about adding packages before you proceed.</strong>)</p>
<ol>
<li><p>Swift OpenAPI Generator – <a target="_blank" href="https://github.com/apple/swift-openapi-generator">https://github.com/apple/swift-openapi-generator</a> – The Core Generator Plugin.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047376776/b1d7b2d0-9b1f-45c8-8c74-4395a4c80dd9.png" alt="Adding Swift OpenAPI Generator to our Project" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047411622/c6eca0c0-538e-40b5-a9b0-9fa044b60694.png" alt="Making sure that no targets are selected for the OpenAPIGenerator" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
</li>
<li><p>Swift OpenAPI Runtime – <a target="_blank" href="https://github.com/apple/swift-openapi-runtime">https://github.com/apple/swift-openapi-runtime</a> – This contains the common types and protocols used by the code generated by the generator plugin.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047457532/846ec488-cfed-4ca5-811b-c38dba0aaf30.png" alt="Adding OpenAPIRuntime to our project" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
</li>
<li><p>Swift OpenAPI URLSession – <a target="_blank" href="https://github.com/apple/swift-openapi-urlsession">https://github.com/apple/swift-openapi-urlsession</a> – This is a transport layer that allows the generated code to use the Apple URLSession to make network requests. </p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753047476699/9556047e-cc33-44b4-9980-0c692d4c1d01.png" alt="Adding OpenAPIURLSession to our Project" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
</li>
</ol>
<p>One major caveat to note here when adding these packages is that <strong>The Swift OpenAPI Generator</strong> should <strong>not</strong> be added to your project target. This is because we’re only using this to generate the code, but we’re not using it in the app.</p>
<p>If you get this error: <code>swift-openapi-generator/Sources/_OpenAPIGeneratorCore/PlatformChecks.swift:21:5 _OpenAPIGeneratorCore is only to be used by swift-openapi-generator itself—your target should not link this library or the command line tool directly.</code> – then you made this mistake.</p>
<p>The easiest way to fix this is removing the package and adding it again. Or you can go to <code>Project → Target → Build Phases → Link Binary with Libraries → Remove Swift OpenAPI Generator</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753048265985/100428a4-e46a-4aa1-8fcf-4c74e26ffed6.png" alt="Where to check if you encounter that error" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>Now that we added these generator and runtime plugins, we need to give the generator some instructions on what to generate. You can do this with an <code>openapi-generator-config.yaml</code> file. For our project, use the following file. It’s really simple:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">generate:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">types</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">client</span>
</code></pre>
<p>This tells our generator to generate the <strong>types</strong> – the swift structs, enums, and so on from the schema section of the file, and the <strong>client</strong> – the main class which interacts with the networking logic.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753048237863/963d6bc0-a368-427b-add3-75dcf4bd3edf.png" alt="openapi-generator-config.yaml file" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>Save this into an <code>openapi-generator-config.yaml</code> file as shown.</p>
<p>And finally, we want the generator to run whenever we want to build this application/target. We can specify this in the Build Phases tab of the target. Under the “ Target → Build Phases → Run Build Tool Plug-ins” , add the OpenAPIGenerator Plugin.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753048334094/24e20adc-c6e0-4d66-965b-19d476a5ffd3.png" alt="Adding the generator in the build phase" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>The first time the project is built after setting this, Xcode will display a security dialog. This will let us “Trust and Enable” for this plugin. It’s a one time confirmation that gives this plugin the permission required to run during the build process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753048374405/6ff51ff4-d33a-4920-b95f-9fda0ee0aef4.png" alt="Trust and Enable security dialog for the generator" class="image--center mx-auto" width="1512" height="1012" loading="lazy"></p>
<p>As soon as you build the second time after giving these permissions, you will generate the files. You might not see any changes in the Xcode window itself. But if you’re curious to see the result, go to this folder. </p>
<p><code>DerivedData →  &lt;ProjectName&gt;*identifier → Build → intermediates.noindex → BuildToolPluginIntermediates → &lt;TargetName&gt;.output → &lt;TargetName&gt; → OpenAPIGenerator → GeneratedSources</code></p>
<p>More on derived data folder here: <a target="_blank" href="https://gayeugur.medium.com/derived-data-2e9468c6da9b">https://gayeugur.medium.com/derived-data-2e9468c6da9b</a> if you’re curious.</p>
<p>Keep in mind that this location might vary based on Xcode version, OpenAPI version, and your project settings. But you don’t need to worry about the file location.</p>
<p>You will see three files called Client.swift, Types.swift, and Server.swift.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753048508703/8fcec6bf-ad86-47de-b57c-7dca22256e06.png" alt="Generated Files" class="image--center mx-auto" width="1148" height="710" loading="lazy"></p>
<p>These are the files that the our generator created and populated with the types and functions we need.</p>
<p>In the next section, we discuss how to use these files to make calls to the server.</p>
<h3 id="heading-step-3-write-a-wrapper">Step 3: Write a wrapper</h3>
<p>While it’s certainly possible to make the calls to server using just the generated code (<code>Client</code>) type throughout our application, a more maintainable approach is to use a wrapper around these types. This will provide a stable, clean interface for the rest our our app to use, and it decouples feature code from the generated code.</p>
<p>I can hear you thinking: “Wait a second. Isn’t the entire purpose of generating this code to avoid this boilerplate abstraction?”</p>
<p>While it adds some abstraction on top of the generated code, it’s valuable to have this for number of reasons. Here are but a few of them:</p>
<ol>
<li><p>Better naming. The generated <code>Post</code> struct right now will be called <code>Components.Schemas.Post</code>.</p>
</li>
<li><p>If you ever want to move away from the generator, an abstraction is really helpful.</p>
</li>
<li><p>If you want to Mock this server call, you can do this via the abstraction.</p>
</li>
<li><p>UI Optimization. You might want to flatten the structure of a model to reduce the number of computed variables in there, and so on.</p>
</li>
</ol>
<p>So, we want to wrap this around a file called <code>WebService.swift</code>:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// WebService.swift</span>
<span class="hljs-keyword">import</span> Foundation
<span class="hljs-keyword">import</span> OpenAPIURLSession

<span class="hljs-comment">// A clean, app-specific Post model.</span>
<span class="hljs-comment">// This decouples views from the generated types.</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AppPost</span>: <span class="hljs-title">Identifiable</span>, <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> id: <span class="hljs-type">Int</span>
    <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> body: <span class="hljs-type">String</span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebService</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> client: <span class="hljs-type">Client</span>

    <span class="hljs-keyword">init</span>() {
        <span class="hljs-comment">// The server URL and transport are from the generated code.</span>
        <span class="hljs-comment">// `Servers.Server1.url()` corresponds to the first URL in the `servers` array of the spec.</span>
        <span class="hljs-keyword">self</span>.client = <span class="hljs-type">Client</span>(
            serverURL: <span class="hljs-keyword">try</span>! <span class="hljs-type">Servers</span>.<span class="hljs-type">Server1</span>.url(),
            transport: <span class="hljs-type">URLSessionTransport</span>()
        )
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getPosts</span><span class="hljs-params">()</span></span> async <span class="hljs-keyword">throws</span> -&gt; [<span class="hljs-type">AppPost</span>] {
        <span class="hljs-comment">// Call the generated method, which was named using `operationId`.</span>
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">try</span> await client.getPosts(.<span class="hljs-keyword">init</span>())

        <span class="hljs-comment">// The generated response is a type-safe enum covering all documented status codes.</span>
        <span class="hljs-keyword">switch</span> response {
        <span class="hljs-keyword">case</span>.ok(<span class="hljs-keyword">let</span> okResponse):
            <span class="hljs-comment">// The body is also a type-safe enum for different content types.</span>
            <span class="hljs-keyword">switch</span> okResponse.body {
            <span class="hljs-keyword">case</span>.json(<span class="hljs-keyword">let</span> posts):
                <span class="hljs-comment">// Map the generated `Components.Schemas.Post` to our clean `AppPost` model.</span>
                <span class="hljs-keyword">return</span> posts.<span class="hljs-built_in">map</span> { post <span class="hljs-keyword">in</span>
                    <span class="hljs-type">AppPost</span>(id: post.id, title: post.title, body: post.body)
                }
            }
        <span class="hljs-comment">// The generator forces the handling of other documented responses.</span>
        <span class="hljs-comment">// Our simple spec only has a 200, so any other response is undocumented.</span>
        <span class="hljs-keyword">case</span>.undocumented(statusCode: <span class="hljs-keyword">let</span> statusCode, <span class="hljs-number">_</span>):
            <span class="hljs-keyword">throw</span> <span class="hljs-type">URLError</span>(.badServerResponse, userInfo: [<span class="hljs-string">"statusCode"</span>: statusCode])
        }
    }
}
</code></pre>
<p>Let’s go through this file to understand what we’re doing.</p>
<p>First, we import <code>OpenAPIUrlSession</code> along with <code>Foundation</code>. This allows us to call the server, get a response and parse that response.</p>
<p>Next, we define the new <code>AppPost</code> struct. This is meant to be the representation of a <code>Post</code> in the App. In the generated <code>Types.Swift</code> file, we have the generated <code>Post</code> structure. This is defined as:</p>
<pre><code class="lang-swift"><span class="hljs-comment">/// - Remark: Generated from `#/components/schemas/Post`.</span>
        <span class="hljs-keyword">internal</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Post</span>: <span class="hljs-title">Codable</span>, <span class="hljs-title">Hashable</span>, <span class="hljs-title">Sendable</span> </span>{
            <span class="hljs-comment">/// - Remark: Generated from `#/components/schemas/Post/userId`.</span>
            <span class="hljs-keyword">internal</span> <span class="hljs-keyword">var</span> userId: <span class="hljs-type">Swift</span>.<span class="hljs-type">Int</span>
            <span class="hljs-comment">/// - Remark: Generated from `#/components/schemas/Post/id`.</span>
            <span class="hljs-keyword">internal</span> <span class="hljs-keyword">var</span> id: <span class="hljs-type">Swift</span>.<span class="hljs-type">Int</span>
            <span class="hljs-comment">/// - Remark: Generated from `#/components/schemas/Post/title`.</span>
            <span class="hljs-keyword">internal</span> <span class="hljs-keyword">var</span> title: <span class="hljs-type">Swift</span>.<span class="hljs-type">String</span>
            <span class="hljs-comment">/// - Remark: Generated from `#/components/schemas/Post/body`.</span>
            <span class="hljs-keyword">internal</span> <span class="hljs-keyword">var</span> body: <span class="hljs-type">Swift</span>.<span class="hljs-type">String</span>
            <span class="hljs-comment">/// Creates a new `Post`.</span>
            <span class="hljs-comment">///</span>
            <span class="hljs-comment">/// - Parameters:</span>
            <span class="hljs-comment">///   - userId:</span>
            <span class="hljs-comment">///   - id:</span>
            <span class="hljs-comment">///   - title:</span>
            <span class="hljs-comment">///   - body:</span>
            <span class="hljs-keyword">internal</span> <span class="hljs-keyword">init</span>(
                userId: <span class="hljs-type">Swift</span>.<span class="hljs-type">Int</span>,
                id: <span class="hljs-type">Swift</span>.<span class="hljs-type">Int</span>,
                title: <span class="hljs-type">Swift</span>.<span class="hljs-type">String</span>,
                body: <span class="hljs-type">Swift</span>.<span class="hljs-type">String</span>
            ) {
                <span class="hljs-keyword">self</span>.userId = userId
                <span class="hljs-keyword">self</span>.id = id
                <span class="hljs-keyword">self</span>.title = title
                <span class="hljs-keyword">self</span>.body = body
            }
            <span class="hljs-keyword">internal</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">CodingKeys</span>: <span class="hljs-title">String</span>, <span class="hljs-title">CodingKey</span> </span>{
                <span class="hljs-keyword">case</span> userId
                <span class="hljs-keyword">case</span> id
                <span class="hljs-keyword">case</span> title
                <span class="hljs-keyword">case</span> body
            }
        }
</code></pre>
<p>As you can see, our <code>AppPost</code> struct is different from this generated type. We omit the <code>userId</code> since we do not care about it (at least for now).</p>
<p>Back to the <code>WebService</code> class, we see a <code>client</code> attribute. This is a generated type variable that will let us interact with the servers. In the initializer of the <code>WebService</code> class, we create a new <code>Client</code> using the first server URL we specified in the schema and use the <code>URLSessionTransport</code> object for making these calls.</p>
<p>We then define our methods. In this case, our <code>getPosts()</code> function which returns <code>[AppPost]</code> array.</p>
<p><code>let response = try await client.getPosts(.init())</code> will call the function <code>getPosts()</code> on the <code>Client</code> object. The <code>Client.getPosts()</code> function here takes in an input struct called <code>Operations.getPosts.Input</code> which is initialized by the <code>.init()</code> passed here.</p>
<p>This generated response is a type-safe enum covering all documented codes. (Currently only <code>200</code> in our yaml file). So, we use a simple switch to look at both these cases and further use more switch statements to get the proper response. You can see how much easier this is than to parse the response manually.</p>
<p>Once we get the <code>Components.Schemas.Post</code> response, we map and convert it into <code>[AppPost]</code> array and return it.</p>
<p>Now, let’s use this wrapper to display data in our app.</p>
<h3 id="heading-step-4-call-the-wrapper-and-display-the-data">Step 4: Call the wrapper and display the data</h3>
<p>We’re at the final step now. We’ll use the wrapper we created to display the fetched posts. We’ll also use a state variable to store our <code>AppPost</code> array in our <code>ContentView</code> view. We’ll then call <code>getPosts()</code> when the view is first displayed to the user.</p>
<pre><code class="lang-swift"><span class="hljs-comment">// ContentView.swift</span>
<span class="hljs-keyword">import</span> SwiftUI

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> posts: [<span class="hljs-type">AppPost</span>] = []
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> errorMessage: <span class="hljs-type">String?</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> webService = <span class="hljs-type">WebService</span>()

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">NavigationStack</span> {
            <span class="hljs-type">List</span>(posts) { post <span class="hljs-keyword">in</span>
                <span class="hljs-type">VStack</span>(alignment:.leading, spacing: <span class="hljs-number">8</span>) {
                    <span class="hljs-type">Text</span>(post.title)
                       .font(.headline)
                    <span class="hljs-type">Text</span>(post.body)
                       .font(.subheadline)
                       .foregroundColor(.secondary)
                }
               .padding(.vertical, <span class="hljs-number">4</span>)
            }
           .navigationTitle(<span class="hljs-string">"Posts"</span>)
           .task {
                await loadPosts()
            }
           .overlay {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> errorMessage {
                    <span class="hljs-type">ContentUnavailableView</span>(<span class="hljs-string">"Error"</span>, systemImage: <span class="hljs-string">"xmark.octagon"</span>, description: <span class="hljs-type">Text</span>(errorMessage))
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> posts.isEmpty {
                    <span class="hljs-type">ProgressView</span>()
                }
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadPosts</span><span class="hljs-params">()</span></span> async {
        <span class="hljs-keyword">self</span>.errorMessage = <span class="hljs-literal">nil</span>
        <span class="hljs-keyword">do</span> {
            <span class="hljs-keyword">self</span>.posts = <span class="hljs-keyword">try</span> await webService.getPosts()
        } <span class="hljs-keyword">catch</span> {
            <span class="hljs-keyword">self</span>.errorMessage = error.localizedDescription
        }
    }
}

#<span class="hljs-type">Preview</span> {
    <span class="hljs-type">ContentView</span>()
}
</code></pre>
<p>You can see the dummy posts in the Preview. As you can see, all we had to do was call the <code>webService.getPosts()</code> to populate the variable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753053957409/b89d50e8-ab73-4484-beda-3a328a575144.png" alt="Simulator Run of the app showing the fetched posts" class="image--center mx-auto" width="1179" height="2556" loading="lazy"></p>
<p>You might be thinking that this is a lot of setup for a simple struct like <code>Post</code> for which we had to create a wrapper called <code>AppPost</code> anyway. But if you had ten types like this and twenty endpoints to call? You wouldn’t have to deal with a lot of repetitive, error-prone code.</p>
<h2 id="heading-potential-pitfalls">Potential Pitfalls</h2>
<p>Unfortunately, no process is perfect. You might still face a lot of issues with generated code and this method. I’ve listed some of them here and how to deal with them.</p>
<h3 id="heading-verbose-or-ugly-generated-code">Verbose or ugly generated code</h3>
<p>If you have very verbose or ugly generated code, the problem is almost always the missing <code>operationId</code> for an API path. If you don’t specify one, the generator must create a name from the path and the HTTP method with results in long unwieldy names. Adding a clear <code>operationId</code> will mitigate this issue.</p>
<h3 id="heading-large-specs-and-performance-issues">Large Specs and Performance Issues</h3>
<p>If you have a very large Spec file, generating a client for this entire specification can significantly increase the compile time. It can also result in absolutely massive <code>Types.swift</code> and <code>Client.swift</code> files.</p>
<p>There is a filter option in the <code>openapi-generator-config.yaml</code> file that will allow the generator to include only parts of the spec that are relevant to the application to improve build times and so on. But if you want everything in an API that has hundreds of endpoints, the only way to reduce compile times is to avoid regenerating this every time and decouple this step from the regular build process.</p>
<h3 id="heading-unsupported-spec-features">Unsupported Spec Features</h3>
<p>While the swift package, <code>swift-openapi-generator</code>, is robust, it does not support all the features included in the specification. I had issues with some features of the newer spec version ( <code>3.1.1</code> and had to downgrade to <code>3.0.3</code> to make it work well ).</p>
<p>There are also known issues like lack of support for certain types of recursive schemas. Sometimes, the generator errors out and fails and some other times, it generates incomplete types – which can result in a few hours of debugging (I speak from experience).</p>
<p>In any case, knowing the limits of this generator can be helpful in avoiding issues it might cause. Also keep in mind that it is always getting better thanks to its open source nature.</p>
<h2 id="heading-conclusion-embrace-spec-driven-development">Conclusion: Embrace Spec-Driven Development</h2>
<p>In this guide, you navigated the journey of adopting <code>swift-openapi-generator</code> – from understanding the power of API contracts to building a functional SwiftUI app. You also learned about the real life challenges of this process. While there is an initial learning curve, the benefits of this approach are profound.</p>
<p>The core tenet of this approach is to foster more disciplined and more robust method for building applications. By making the OpenAPI document the single source of truth, you make sure that both the frontend and backend are perfectly in sync in perpetuity.</p>
<p>Using this approach also results in more type-safe, maintainable code. The result is less time spent on writing boilerplate and debugging random integration errors and more time spent creating the app itself.</p>
<p>For developers ready to explore further, please checkout the official <code>swift-openapi-generator</code> repository on Github here: <a target="_blank" href="https://github.com/apple/swift-openapi-generator">https://github.com/apple/swift-openapi-generator</a>.</p>
<p>You can follow me on <a target="_blank" href="https://github.com/sravankaruturi">GitHub</a> and <a target="_blank" href="https://hashnode.com/@sravankaruturi">Hashnode</a> for my other posts and projects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Address Common Accessibility Challenges in iOS Mobile Apps Using SwiftUI ]]>
                </title>
                <description>
                    <![CDATA[ Mobile apps are essential tools in daily life, making accessibility a top priority. However, many apps still do not provide inclusive experiences for people with disabilities. This article highlights nine common accessibility challenges in mobile app... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-address-ios-accessibility-challenges-using-swiftui/</link>
                <guid isPermaLink="false">673dc0d9ed2a01b66ee9f37c</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Namaswi Chandarana ]]>
                </dc:creator>
                <pubDate>Wed, 20 Nov 2024 10:58:33 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9e9PD9blAto/upload/43ed1bb84a1c0abad81192c63e920503.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Mobile apps are essential tools in daily life, making accessibility a top priority. However, many apps still do not provide inclusive experiences for people with disabilities.</p>
<p>This article highlights nine common accessibility challenges in mobile apps and demonstrates how SwiftUI features can help developers address these issues effectively.</p>
<p>Each challenge is paired with a SwiftUI solution, sample code, and testing tips to guide developers in creating accessible and user-friendly apps.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-mobile-apps-accessibility-issues-and-swiftui-solutions">Mobile Apps Accessibility Issues and SwiftUI Solutions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-missing-labels-and-descriptions">Missing Labels and Descriptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-insufficient-color-contrast">Insufficient Color Contrast</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-small-touch-targets">Small Touch Targets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inaccessible-navigation">Inaccessible Navigation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lack-of-feedback-for-actions">Lack of Feedback for Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-complex-or-confusing-user-interfaces">Complex or Confusing User Interfaces</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lack-of-support-for-assistive-technologies">Lack of Support for Assistive Technologies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-poorly-implemented-accessibility-features">Poorly Implemented Accessibility Features</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-insufficient-customization-options">Insufficient Customization Options</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-references">References</a></p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-mobile-apps-accessibility-issues-and-swiftui-solutions">Mobile Apps Accessibility Issues and SwiftUI Solutions</h2>
<h3 id="heading-missing-labels-and-descriptions">Missing Labels and Descriptions</h3>
<ul>
<li><p><strong>Challenge</strong>: Many apps lack appropriate labels or descriptions for buttons, images, and other interactive elements, making it difficult for screen readers to communicate their purpose to visually impaired users. Without these labels, users might struggle to understand the app’s functionality.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: SwiftUI’s <code>.accessibilityLabel(_:)</code> modifier allows developers to assign clear, descriptive labels to interactive elements. These labels improve navigation and understanding by giving screen readers the necessary context.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Label</span>(<span class="hljs-string">"Shop"</span>, systemImage: <span class="hljs-string">"cart"</span>)
      .accessibilityLabel(<span class="hljs-string">"Go to Shop"</span>)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Enable VoiceOver on an iOS device, navigate through the app, and ensure each element has an accurate label. VoiceOver should read labels clearly to help users understand each element’s purpose without needing additional explanation.</p>
</li>
</ul>
<h3 id="heading-insufficient-color-contrast">Insufficient Color Contrast</h3>
<ul>
<li><p><strong>Challenge</strong>: Low contrast between text and background colors can make it difficult for users with visual impairments to read the content, especially for those with color vision deficiencies or low vision.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use SwiftUI’s dynamic system colors (<code>.primary</code> and <code>.secondary</code>), which automatically adapt to the light or dark mode setting on the device, ensuring good readability.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Shop"</span>)
      .foregroundColor(.primary)  <span class="hljs-comment">// Adapts to light or dark mode automatically</span>
</code></pre>
</li>
<li><p>If custom colors are necessary, test them against WCAG standards for color contrast, using tools like Color Contrast Analyzer.</p>
</li>
<li><p><strong>Testing</strong>: Use Xcode’s Accessibility Inspector to verify contrast, and ensure that text remains readable in both light and dark modes. WCAG guidelines recommend a minimum contrast ratio of 4.5:1 for normal text.</p>
</li>
</ul>
<h3 id="heading-small-touch-targets">Small Touch Targets</h3>
<ul>
<li><p><strong>Challenge</strong>: Small buttons or other touch areas can be difficult for users with motor impairments to interact with accurately. Elements that are too small may require more precision than some users can provide.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Set minimum touch sizes by adding padding or using <code>.frame(minWidth:minHeight:)</code> to ensure a comfortable touch target size.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Button</span>(action: { <span class="hljs-comment">/* Action */</span> }) {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Tap Me"</span>)
          .frame(minWidth: <span class="hljs-number">44</span>, minHeight: <span class="hljs-number">44</span>)
  }.padding()
</code></pre>
</li>
<li><p><strong>Testing</strong>: Manually interact with touch elements in the app on an iOS device. Ensure they are easily tappable without precise effort. Verify touch target size with the Accessibility Inspector to confirm they meet recommended minimums (44x44 points).</p>
</li>
</ul>
<h3 id="heading-inaccessible-navigation">Inaccessible Navigation</h3>
<ul>
<li><p><strong>Challenge</strong>: Apps with limited navigability can cause frustration for users who rely on screen readers or keyboards. Without a clear reading order, navigating through the interface becomes challenging.</p>
</li>
<li><p><strong>SwiftUI Techniques for Accessible Navigation</strong>:</p>
<ul>
<li><p><strong>Group Elements</strong> with <code>.accessibilityElement(children:)</code>: Combine related elements into a single accessible unit for more streamlined navigation.</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Profile"</span>)
      <span class="hljs-type">Image</span>(<span class="hljs-string">"profile_picture"</span>)
  }
  .accessibilityElement(children: .combine)
</code></pre>
</li>
<li><p><strong>Set Focus</strong> with <code>.accessibilityFocused</code>: Programmatically control focus on specific elements.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Special Announcement"</span>)
      .accessibilityFocused($isFocused)
</code></pre>
</li>
<li><p><strong>Custom Actions</strong> with <code>.accessibilityAction</code>: Add specific actions for interactive controls like sliders or steppers.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Slider</span>(value: $value)
      .accessibilityAction(named: <span class="hljs-string">"Increase"</span>) { value += <span class="hljs-number">10</span> }
</code></pre>
</li>
<li><p><strong>Hide Decorative Elements</strong> with <code>.accessibilityHidden</code>: Exclude non-essential visuals from screen readers.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Image</span>(<span class="hljs-string">"decorative_image"</span>)
      .accessibilityHidden(<span class="hljs-literal">true</span>)
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Testing</strong>: Enable VoiceOver and use swipe gestures to confirm the intended focus order. Also, use a connected keyboard or switch control to test smooth transitions and confirm navigability.</p>
</li>
</ul>
<h3 id="heading-lack-of-feedback-for-actions">Lack of Feedback for Actions</h3>
<ul>
<li><p><strong>Challenge</strong>: Without feedback, users with visual or hearing impairments may struggle to confirm if an action has completed. Feedback like haptic, auditory, or visual cues can enhance usability.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use <code>.accessibilityHint</code> to provide additional information about the action that will occur.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Button</span>(<span class="hljs-string">"Submit"</span>) {
      <span class="hljs-comment">// Submit action</span>
  }.accessibilityHint(<span class="hljs-string">"Submits the form"</span>)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Use VoiceOver to ensure that hints are read immediately after labels. Check that users can understand what each button does without extra explanation.</p>
</li>
</ul>
<h3 id="heading-complex-or-confusing-user-interfaces">Complex or Confusing User Interfaces</h3>
<ul>
<li><p><strong>Challenge</strong>: Cluttered interfaces can be overwhelming, particularly for users with cognitive impairments, who may struggle to navigate or process information effectively.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Simplify layouts and use <code>.accessibilitySortPriority</code> to organize the reading order logically.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Main Content"</span>)
          .accessibilitySortPriority(<span class="hljs-number">1</span>)
      <span class="hljs-type">Button</span>(<span class="hljs-string">"Secondary Action"</span>)
          .accessibilitySortPriority(<span class="hljs-number">2</span>)
  }
</code></pre>
</li>
<li><p><strong>Testing</strong>: Use VoiceOver to verify the logical reading order and ensure only relevant elements are accessible. Use <code>.accessibilityHidden</code> to hide decorative elements that do not add meaningful information.</p>
</li>
</ul>
<h3 id="heading-lack-of-support-for-assistive-technologies">Lack of Support for Assistive Technologies</h3>
<ul>
<li><p><strong>Challenge</strong>: Inadequate support for screen readers or other assistive technologies can make apps unusable for some users.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Group elements with <code>.accessibilityElement(children: .combine)</code> for cohesive navigation. This improves readability and usability for screen reader users.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Profile"</span>)
      <span class="hljs-type">Image</span>(<span class="hljs-string">"profile_picture"</span>)
  }
  .accessibilityElement(children: .combine)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Check with VoiceOver that grouped elements are announced as a single unit, improving navigation flow for visually impaired users.</p>
</li>
</ul>
<h3 id="heading-poorly-implemented-accessibility-features">Poorly Implemented Accessibility Features</h3>
<ul>
<li><p><strong>Challenge</strong>: Without regular testing and updates, accessibility features can degrade over time, negatively impacting the user experience.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Regular testing with VoiceOver and Xcode’s Accessibility Inspector helps maintain effective functionality.</p>
</li>
<li><p><strong>Testing</strong>: Conduct regular testing to detect regressions or improvements needed for accessibility. Recheck VoiceOver usability after UI updates to confirm features remain effective.</p>
</li>
</ul>
<h3 id="heading-insufficient-customization-options">Insufficient Customization Options</h3>
<ul>
<li><p><strong>Challenge</strong>: Limited customization options, such as font size or color schemes, restrict usability for users with specific visual needs.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use <code>.dynamicTypeSize()</code> to allow text scaling based on the user’s preferred settings.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Adjustable Text"</span>)
      .dynamicTypeSize(.xxxLarge)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Adjust text size in iOS Accessibility settings, and ensure the app’s text scales correctly without truncating or overlapping, preserving readability.</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ol>
<li><p><strong>Apple Developer Documentation: SwiftUI Accessibility</strong></p>
<ul>
<li><p>Comprehensive guide to accessibility in SwiftUI, covering accessibility properties like <code>.accessibilityLabel</code>, <code>.accessibilityHint</code>, <code>.accessibilityElement</code>, and more.</p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/documentation/swiftui/accessibility">SwiftUI Accessibility Guide</a></p>
</li>
</ul>
</li>
<li><p><strong>Apple Human Interface Guidelines: Accessibility</strong></p>
<ul>
<li><p>Apple's best practices for designing accessible apps, including color contrast and touch target size recommendations.</p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/">Apple Human Interface Guidelines: Accessibility</a></p>
</li>
</ul>
</li>
<li><p><strong>Color Contrast Analyzer</strong></p>
<ul>
<li><p>A tool for testing contrast ratios to ensure color accessibility compliance with WCAG standards.</p>
</li>
<li><p>Color Contrast Analyzer</p>
</li>
</ul>
</li>
<li><p><strong>VoiceOver and Accessibility Inspector</strong></p>
<ul>
<li><p>Tools for testing accessibility features, available in iOS and Xcode for simulating screen reader usage and checking accessibility properties.</p>
</li>
<li><p><a target="_blank" href="https://support.apple.com/guide/voiceover/welcome/mac">VoiceOver Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/documentation/accessibility-testing/accessibility-inspector">Accessibility Inspector Documentation</a></p>
</li>
</ul>
</li>
<li><p><strong>Chandarana, N., &amp; Gada, T. (2024). Accessibility Challenges in Current Mobile Applications: A Comprehensive Overview.</strong></p>
<ul>
<li><p>This journal paper provides an in-depth analysis of common accessibility challenges faced in mobile applications, discussing real-world examples and potential solutions for developers.</p>
</li>
<li><p><em>International Journal of Innovative Research in Computer and Communication Engineering.</em></p>
</li>
</ul>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement a GameKit Leaderboard in SwiftUI ]]>
                </title>
                <description>
                    <![CDATA[ By Saamer Mansoor In this article we will talk about why and how to implement the GameCenter's Leaderboard within your app.  Why GameCenter is Making a Huge Revival You can make iPhone games without a scoreboard, but leaderboards can help make the ga... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-a-leaderboard-in-swiftui/</link>
                <guid isPermaLink="false">66d460c537bd2215d1e245bb</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Games ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 19 Aug 2022 21:00:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/07/IMG_45B142A26F90-1-copy.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Saamer Mansoor</p>
<p>In this article we will talk about why and how to implement the <a target="_blank" href="https://developer.apple.com/design/human-interface-guidelines/technologies/game-center/leaderboards/">GameCenter's Leaderboard</a> within your app. </p>
<h2 id="heading-why-gamecenter-is-making-a-huge-revival">Why GameCenter is Making a Huge Revival</h2>
<p>You can make iPhone games without a scoreboard, but leaderboards can help make the game feel more competitive, like people are competing against one another around the World. </p>
<p>Instead of creating and managing your own backend, the GameCenter Leaderboard allows you to scale with traffic infinitely, skip an entire login page for authorization, get the Image, Name, and friends playing the same game – all without your users having to enter anything. </p>
<p>Especially with iOS 16, <a target="_blank" href="https://developer.apple.com/game-center/">Apple is investing more in improving it</a>, and driving more app usage, like through Push Notifications when your friend beats your score in the game.</p>
<p>In my journey of learning SwiftUI, I have been creating and publishing apps, because IMO that's the best way to learn. </p>
<p>There wasn't much updated documentation on how to do a lot of this, especially none with SwiftUI nor with the <a target="_blank" href="https://www.freecodecamp.org/news/make-rest-api-call-in-swiftui-in-2-minutes/">advent of async and await in Swift</a>. So I consolidated and simplified it for everyone to build amazing apps. So feel free to invite me to test your apps too!</p>
<h3 id="heading-pre-requisites">Pre-Requisites:</h3>
<ul>
<li>You'll need to have an <a target="_blank" href="https://developer.apple.com/programs/">Apple Developer</a> paid account</li>
<li>You have to create the <a target="_blank" href="https://support.magplus.com/hc/en-us/articles/203808708-iOS-Creating-App-IDs">App Id for your app</a> in the provisioning profiles section of the Apple Developer Portal</li>
<li>You have to <a target="_blank" href="https://support.staffbase.com/hc/en-us/articles/115003481992-Creating-an-App-Profile-in-App-Store-Connect">create the App in the iTunes Connect Connect</a> portal</li>
</ul>
<h2 id="heading-how-to-implement-your-ios-leaderboard-in-6-steps">How to Implement Your iOS Leaderboard in 6 Steps</h2>
<p>Most of the code logic for the leaderboard is in <a target="_blank" href="https://github.com/StairMasterClimber/mobile/blob/main/StairStepperMaster/StairStepperMaster/Views/LeadersTileView.swift">this file if you want to skip ahead</a>. Here's the steps as follows:</p>
<h3 id="heading-1-how-to-create-the-app-store-connect-leaderboard">1. How to Create the App Store Connect Leaderboard</h3>
<p><img src="https://user-images.githubusercontent.com/8262287/180824532-2e27ca8a-c1c0-4676-b439-f3ab09887271.png" alt="image" width="1348" height="754" loading="lazy">
<em>Screenshot from the Apple iTunes Connect Portal</em></p>
<p>Once you have created the app in the App Store Connect portal successfully, go to the Services tab for the app -&gt; and make sure you're in the GameCenter page.</p>
<p>Then add a new leaderboard using the "+" sign, which can either be "Classic" (scores never reset) or "Recurring" (scores reset based on your frequency settings).</p>
<p>Most games prefer a recurring leaderboard so that the leaderboard isn't cluttered with older impossible to reach high scores.</p>
<p>The LeaderboardID you input there is the one that you need to use in all the places in the code that ask for it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-122.png" alt="Image" width="600" height="400" loading="lazy">
<em>Details required to create a new Leaderboard</em></p>
<h3 id="heading-2-how-to-set-up-gamecenter-authentication">2. How to Set Up GameCenter Authentication</h3>
<p>First, you'll need to authenticate users to GameCenter in order for any of this functionality to work.</p>
<p>So we'll use this code to do that, which basically makes sure that you (GKLocalPlayer.local) are authenticated, or prints an error if there is one:</p>
<pre><code>func authenticateUser() {
    GKLocalPlayer.local.authenticateHandler = { vc, error <span class="hljs-keyword">in</span>
        guard error == nil <span class="hljs-keyword">else</span> {
            print(error?.localizedDescription ?? <span class="hljs-string">""</span>)
            <span class="hljs-keyword">return</span>
        }
    }
}
</code></pre><p>If the user is authenticated, you will see a little popup in the UI. If not, the user will be taken to a page to login to their GameCenter account.</p>
<p><img src="https://user-images.githubusercontent.com/8262287/180823235-cafefcfa-3d25-46e5-8524-d7f475b9a000.png" alt="image" width="464" height="94" loading="lazy">
<em>A sign that displays when a user is logged in</em></p>
<h3 id="heading-3-how-to-display-leaderboard-items-in-the-ui">3. How to Display Leaderboard Items in the UI</h3>
<p>In order to get the data away from the GameCenter ViewController leaderboards (GKLeaderboard), you need to use the <code>loadLeaderboards</code> . </p>
<p>You can switch up the <code>loadEntries</code> function from <code>.global</code> to <code>.friends</code> in order to only pull your friends. </p>
<p>You can also retrieve the image for each player by iterating over each player and performing a <code>loadPhoto</code>. </p>
<p>Using <code>NSRang(1...5)</code>, you can choose how many players to display. This pulls the users with the highest 5 scores from the leaderboard and returns none if there's no users, such as in the case when the cycle refreshes for a recurring Leaderboard.</p>
<p>This is what pulling data from a leaderboard could look like if you take advantage of async-await:</p>
<pre><code>func loadLeaderboard() <span class="hljs-keyword">async</span> {
    playersList.removeAll()
    Task{
        <span class="hljs-keyword">var</span> playersListTemp : [Player] = []
        <span class="hljs-keyword">let</span> leaderboards = <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> GKLeaderboard.loadLeaderboards(IDs: [leaderboardIdentifier])
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> leaderboard = leaderboards.filter ({ $<span class="hljs-number">0.</span>baseLeaderboardID == self.leaderboardIdentifier }).first {
            <span class="hljs-keyword">let</span> allPlayers = <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> leaderboard.loadEntries(<span class="hljs-keyword">for</span>: .global, <span class="hljs-attr">timeScope</span>: .allTime, <span class="hljs-attr">range</span>: NSRange(<span class="hljs-number">1.</span>.<span class="hljs-number">.5</span>))
            <span class="hljs-keyword">if</span> allPlayers<span class="hljs-number">.1</span>.count &gt; <span class="hljs-number">0</span> {
                <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> allPlayers<span class="hljs-number">.1</span>.asyncForEach { leaderboardEntry <span class="hljs-keyword">in</span>
                    <span class="hljs-keyword">var</span> image = <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> leaderboardEntry.player.loadPhoto(<span class="hljs-keyword">for</span>: .small)
                    playersListTemp.append(Player(name: leaderboardEntry.player.displayName, <span class="hljs-attr">score</span>:leaderboardEntry.formattedScore, <span class="hljs-attr">image</span>: image))
                                print(playersListTemp)
                    playersListTemp.sort{
                        $<span class="hljs-number">0.</span>score &lt; $<span class="hljs-number">1.</span>score
                    }
                }
            }
        }
        playersList = playersListTemp            
    }
}
</code></pre><p><img src="https://user-images.githubusercontent.com/8262287/180823292-2dee4f9a-4894-4442-9241-2ad1c84b1cf7.png" alt="image" width="622" height="240" loading="lazy">
<em>You can get leaderboard data into your app</em></p>
<h3 id="heading-4-how-to-call-functionality-in-swiftui-as-the-viewpage-appears">4. How to Call Functionality in SwiftUI as the View/Page Appears</h3>
<p>You can take advantage of the <code>onAppear</code> <a target="_blank" href="https://www.hackingwithswift.com/quick-start/swiftui/how-to-respond-to-view-lifecycle-events-onappear-and-ondisappear">lifecycle function of the view</a> to actually make the calls to authenticate and load, but you can also do it on the tap of a button if you prefer that:</p>
<pre><code>.onAppear(){
    <span class="hljs-keyword">if</span> !GKLocalPlayer.local.isAuthenticated {
        authenticateUser()
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> playersList.count == <span class="hljs-number">0</span> {
        Task{
            <span class="hljs-keyword">await</span> loadLeaderboard()
        }
    }
}
</code></pre><h3 id="heading-5-how-to-load-the-submitted-scores">5. How to Load the Submitted Scores</h3>
<p>In order to load the scores, you need to submit them as well. The <code>submitScore</code> function can help you with that.</p>
<ul>
<li>The <code>flightsClimbed</code> variable should contain the score that you would like to submit.</li>
<li>GameKit makes sure to only display your best score for the life of the leaderboard.</li>
<li>The <code>leaderboardId</code> contains the value that you manually enter in your App Store Connect account:</li>
</ul>
<pre><code>func leaderboard() <span class="hljs-keyword">async</span>{
    Task{
        <span class="hljs-keyword">try</span> <span class="hljs-keyword">await</span> GKLeaderboard.submitScore(
            flightsClimbed,
            <span class="hljs-attr">context</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">player</span>: GKLocalPlayer.local,
            <span class="hljs-attr">leaderboardIDs</span>: [<span class="hljs-string">"com.tfp.stairsteppermaster.flights"</span>]
        )
    }
    calculateAchievements()
}
</code></pre><h3 id="heading-6-how-to-display-the-gamecenter-viewcontroller-portal">6. How to display the GameCenter ViewController Portal</h3>
<p>When you're logged into GameCenter, a little annoying icon appears in the top right of your screen. When you tap on it, you are taken to the GameCenter ViewController. Luckily you can hide it if it's not part of your design, using <code>GKAccessPoint.shared.isActive = false</code>. </p>
<p>Since the GameCenter UI is a UIKit <code>ViewController</code> and not a simple SwiftUI <code>View</code>, you need to create this <a target="_blank" href="https://www.hackingwithswift.com/books/ios-swiftui/wrapping-a-uiviewcontroller-in-a-swiftui-view">UIViewControllerRepresentable</a> first (as you can <a target="_blank" href="https://github.com/StairMasterClimber/mobile/blob/main/StairStepperMaster/StairStepperMaster/Views/GameCenterView.swift">see here</a>), to launch GameCenter using a different button, </p>
<p>Once you add that file to your project, you can display the GameCenter portal simply using this: <code>GameCenterView(format: gameCenterViewControllerState)</code> where gameCenterViewControllerState can be help you go to a detail page in GameCenter.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Frame-3-3.png" alt="Image" width="600" height="400" loading="lazy">
<em>GameCenter's Leaderboard View</em></p>
<h2 id="heading-things-to-keep-in-mind-while-using-gamecenters-leaderboards">Things to Keep in Mind While using GameCenter's Leaderboards:</h2>
<ul>
<li>Simulator Debugging – For some reason the authenticate to GameCenter is extremely slow on a simulator, so it might make sense to even create a mock of data when using the simulator.</li>
<li>Challenges – You can't programmatically issue GameKit Challenges to your friends anymore <a target="_blank" href="https://developer.apple.com/documentation/gamekit/gkscore/1520610-issuechallenge">due to deprecation</a>. Instead, you have to do those manually within the user's GameCenter dashboard against GameKit Achievements. Also, there's no way to view challenges you have sent. </li>
<li>Achievements – Leaderboards are different from the GameKit Achievements, which is calculated and displayed differently, but a <a target="_blank" href="https://github.com/StairMasterClimber/mobile/blob/18283a68e1c5cac4e270a85b03853887b3950156/StairStepperMaster/StairStepperMaster/Views/AchievementTileView.swift#L113">lot easier</a>. Those can also be pulled into the app as well, as you can see below:</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Frame-2-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>GameKit Challenges and Achievements</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>You can try out the free open-source <a target="_blank" href="https://stairmasterclimber.com/app">Stair Master Climber iPhone Health &amp; Fitness app</a> that I shared above. I would love to know what you think so that we can learn together. </p>
<p>Feel free to reach out to me on <a target="_blank" href="https://twitter.com/StairMasterApp">social media</a> or by <a target="_blank" href="mailto:hi@stairmasterclimber.com">email</a> if you have any questions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make a Simple Async GET REST API call in SwiftUI ]]>
                </title>
                <description>
                    <![CDATA[ By Saamer Mansoor In this tutorial for beginners, you will learn the basics of using SwiftUI to make API calls using the popular Internet Chuck Norris DataBase (ICNDB) as an example. It will display a joke quickly and easily using Swift and SwiftUI. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/make-rest-api-call-in-swiftui-in-2-minutes/</link>
                <guid isPermaLink="false">66d460c7d7a4e35e384349ab</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 02 Dec 2021 18:32:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/12/Frame-12-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Saamer Mansoor</p>
<p>In this tutorial for beginners, you will learn the basics of using SwiftUI to make API calls using the popular Internet Chuck Norris DataBase (ICNDB) as an example. It will display a joke quickly and easily using Swift and SwiftUI. </p>
<p>You'll see how the cross-platform framework SwiftUI lets us use the exact same code across iOS, iPadOS, macOS, watchOS, App Clips and tvOS, which otherwise would have been impossible.</p>
<p>Along with that, you will use <a target="_blank" href="https://developer.apple.com/documentation/swift/swift_standard_library/concurrency/updating_an_app_to_use_swift_concurrency">async-await</a> that was introduced in Swift 5.5, which works for newer operating systems including iPhones running iOS &gt; v15.0. This really simplifies our work of making data network calls asynchronously on click of a button without freezing the UI thread. </p>
<p>I will share the code changes you'll need to make first. Then in the following section, I will share a brief analysis of the code so beginners can understand what's going on as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Group-1-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>tvOS app running the code displays a button that retrieves the joke on click</em></p>
<h2 id="heading-how-to-make-api-calls-in-swift-and-swiftui">How to Make API Calls in Swift and SwiftUI</h2>
<p>First, you'll need a Mac to install Xcode. Once it's installed, open Xcode and create a new project. Then select "App" for iOS, macOS, tvOS, or watchOS.</p>
<h3 id="heading-contentview">ContentView</h3>
<p>Just update your existing ContentView SwiftUI file to add a Button and use the <em>State</em> variable to refresh the text displayed as the joke returns from ICNDB API:</p>
<pre><code class="lang-swiftui">import Foundation
import SwiftUI
struct ContentView: View {
    @State private var joke: String = ""
    var body: some View {
        Text(joke)
        Button {
            Task {
                let (data, _) = try await URLSession.shared.data(from: URL(string:"https://api.chucknorris.io/jokes/random")!)
                let decodedResponse = try? JSONDecoder().decode(Joke.self, from: data)
                joke = decodedResponse?.value ?? ""
            }
        } label: {
            Text("Fetch Joke")
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct Joke: Codable {
    let value: String
}
</code></pre>
<h3 id="heading-fetch-a-joke">Fetch a joke!</h3>
<p>If you press build/play, the app will build in whatever platform you selected above:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screen-Shot-2021-12-01-at-4.42.11-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshots of watchOS, macOS, and iOS apps running the same exact code</em></p>
<h2 id="heading-code-analysis">Code Analysis</h2>
<p>If you go to the random joke URL, you'll notice that the data is in JSON format. You can copy that and use a JSON Linter to view its structure to figure out what property of the Joke object is needed. </p>
<p>Based on that, you determine the code above. You use the Codable protocol (aka interfaces) to go from a JSON data object to an actual Swift class or struct, and you create properties for the data you want to store (value in our case). </p>
<p>JSONDecoder helps us parse the JSON string using the Codable object. This works regardless of platform because the page that loads on launching the app has the same name <em>ContentView</em> regardless of platform.</p>
<h3 id="heading-app-clips">App Clips</h3>
<p><a target="_blank" href="https://developer.apple.com/app-clips/">App Clips</a> are Apple's latest way of using native app functionality using an "App Clip Code" without having to download the whole application from the App Store.</p>
<p>App Clips work similar to an iOS app – the only difference is that you don't create a new App Clip project. You just need to add the App Clip as a target to an existing iOS app by going to File-&gt;New-&gt;Target-&gt;iOS-&gt;App Clip when an existing iOS app is open in Xcode. </p>
<p>If you you wondering about iPhone/iPad <a target="_blank" href="https://support.apple.com/en-us/HT207122">Widgets</a>, well they don't animate. So button clicks will just open the corresponding app and can't update text through an external API independently. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned how to make RESTful GET API calls from SwiftUI in the simplest possible way! </p>
<p>Feel free to reach out to me if you have any questions. I figured this out using another article and I thought of simplifying it further. So for more details and ways to make this code more complex, check out that article:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.raywenderlich.com/25013447-async-await-in-swiftui">https://www.raywenderlich.com/25013447-async-await-in-swiftui</a></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build design system with SwiftUI ]]>
                </title>
                <description>
                    <![CDATA[ By Vince MingPu Shao Building a design system to support one product is not easy - it has to be robust and flexible at the same time for scalability. Though challenging, lots of great resources have shared useful principles and approaches that help t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-design-system-with-swiftui/</link>
                <guid isPermaLink="false">66d4617736c45a88f96b7d13</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design Systems ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 09 Sep 2019 23:42:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/preview-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Vince MingPu Shao</p>
<p>Building a design system to support one product is not easy - it has to be robust and flexible at the same time for scalability. Though challenging, <a target="_blank" href="https://www.designbetter.co/design-systems-handbook/building-design-system">lots</a> <a target="_blank" href="https://lightningdesignsystem.com/design-tokens/">of</a> <a target="_blank" href="https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421">great</a> <a target="_blank" href="https://www.youtube.com/watch?v=wDBEc3dJJV8">resources</a> have shared useful principles and approaches that help teams build a good system both visually and programmatically. Standing on their shoulders, this article tries to contribute to an untouched ground by focusing on building a good system in <code>SwiftUI</code>.</p>
<h2 id="heading-why-do-i-write-this-article">Why do I write this article</h2>
<p>During my first summer in <a target="_blank" href="https://tisch.nyu.edu/itp">ITP</a> at New York, I'm lucky to have the opportunity to work as an iOS developer intern at <a target="_blank" href="https://www.linebreak.studio/">Line Break Studio</a>. One task I've been assigned to is building a design system in two steps: first visually in <a target="_blank" href="https://www.sketch.com/">Sketch</a>, and then programmatically in <code>SwiftUI</code>. The experience of experimenting with the new framework and building a design system with it has been amazing, but also buggy along the way. That's why we'd like to share our experience with the community, hopefully making your development process easier.</p>
<hr>
<h2 id="heading-what-is-swiftuihttpsdeveloperapplecomdocumentationswiftui">What is <a target="_blank" href="https://developer.apple.com/documentation/swiftui">SwiftUI</a></h2>
<p>Apple released this groundbreaking new framework in <a target="_blank" href="https://developer.apple.com/videos/wwdc2019/?q=swiftui">WWDC 2019</a>, which is one of the bests in years. From the point of view as a web developer, the project development experience in <code>SwiftUI</code> is closer to which in conventional front-end stack and frameworks.</p>
<p>This is definitely an awesome move because programming interface and managing states are drastically easier than before. And the best part of this improvement is that one can <a target="_blank" href="https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit">integrate UIKit and SwiftUI smoothly</a>. To learn the basics of SwiftUI, the <a target="_blank" href="https://developer.apple.com/tutorials/swiftui/tutorials">official tutorials</a> provided by Apple are very helpful.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/aH7oWxfxpJY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-the-demo-project">The demo project</h2>
<p>For demonstration purpose, I put up a simplified version of design system we built in <a target="_blank" href="https://www.linebreak.studio/">Line Break Studio</a>. It a set of <strong>button</strong> components in different forms, which are built on top of two lower level parts: <strong>typography</strong> and <strong>colorPalette</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/preview-record.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Dynamic rendering view of the demo project</em></p>
<p>The project is <a target="_blank" href="https://github.com/vince19972/SwiftUI-Design-System-Demo">public on GitHub</a>, and I'm using <code>Xcode 11 Beta 5</code> for development. An <a target="_blank" href="https://airtable.com/shrHQdv9vQGz7UMQj">Airtable base</a> as design system management hub (read <a target="_blank" href="https://www.vinceshao.com/blog/a-better-web-development-workflow-confluence-airtable-jira-and-abstract">more about workflow management</a>) is also public for reference.</p>
<hr>
<h2 id="heading-principles-of-building-design-system">Principles of building design system</h2>
<p>Design system in code is a middleware between designers and developers. Developer of the system takes inputs from design system in visual form, and produces API that's identical with which for further development. Following two principles should be recognized to complete this system in code:</p>
<h3 id="heading-1-communicate-with-tokenshttpsmediumcomeightshapes-llctokens-in-design-systems-25dd82d58421">1. Communicate with <a target="_blank" href="https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421">tokens</a></h3>
<p>Fundamentally, the purpose of having a design system in program is not about better code management or development efficiency, but to make sure the <strong>view</strong> is consistent with design files. To achieve that goal, using tokens to signify certain color, font, size or any visual elements is crucial to maintain quality of communication between developers, designers and managers in a team.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/lightning-token.png" alt="Image" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://www.lightningdesignsystem.com/design-tokens/">Lightning Design System</a>'s tokens built by Salesforce</em></p>
<h3 id="heading-2-levels-of-hierarchy">2. Levels of hierarchy</h3>
<p>In <a target="_blank" href="https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421">EightShapes' article</a>, it points out that we should "Show options first, then decisions next", because "You can't make decisions without options."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/eightshape-article.png" alt="Image" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421">EightShapes' article</a> about design tokens</em></p>
<p>This kind of ordering architecture loosens  the degree of coupling between different levels, hence providing more flexibility and dynamic for possible revisions. The way I structure the levels is in this order from bottom to top: material → base → token. But it could be anyway the team's comfortable with.</p>
<hr>
<h2 id="heading-diving-into-code">Diving into code</h2>
<p>Following section is a list of highlights we'd like to point out based on our experience. Please <a target="_blank" href="https://github.com/vince19972/SwiftUI-Design-System-Demo">visit the GitHub repo</a> for complete code. Any feedbacks or critics are welcome for improvements.</p>
<h3 id="heading-1-architecting-levels-of-hierarchy">1. Architecting levels of hierarchy</h3>
<p>There're two ways of stacking materials at lower level to construct tokens at highest level:</p>
<ul>
<li><strong>Use <code>enum</code> for type safety and code literacy</strong></li>
</ul>
<p>Advantages of using enum in code as grouping wrapper or parameter in function have already been well recognized. One point worths mentioning here is the implementation of levels of hierarchy.</p>
<p>We always store the raw values, including font size (<code>CGFloat</code>) and font name (<code>String</code>), at the lowest level, because we don't want to mess around with it. But because raw value must be a literal in enum, we can't just assign a <code>case</code> to be a value from the other enum.</p>
<p>To work around this problem, we implement a function <code>getValue</code>, which returns the raw value in <code>switch</code> case when necessary.</p>




<ul>
<li><strong>Use <code>struct</code> for easier structure</strong></li>
</ul>
<p>Though enum is great, we don't need its unique feature in some cases. For example, because <code>Xcode</code> takes care of the heavy job of processing dynamic colors, and no parameter options are required in API endpoint, we can set up color palettes by simple two levels of struct.</p>




<h3 id="heading-2-clear-and-straightforward-naming-of-api-endpoint">2. Clear and straightforward naming of <code>API</code> endpoint</h3>
<p>Naming convention is another broad topic for discussion and debate. In addition to basic <a target="_blank" href="https://swift.org/documentation/api-design-guidelines/">Swift conventions</a>, the only two rules we abide are, 1) no acronym and 2) making it simple. For example, to use typography and color system, instead of creating new endpoints, we make extension from Font and Color structs. This approach decreases the effort to memorize unfamiliar API names for developers.</p>




<h3 id="heading-3-manage-color-sets-dynamically-in-two-modes">3. Manage color sets dynamically in two modes</h3>
<p>So dark mode has become a standard in industry, and both <a target="_blank" href="https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode/">iOS</a> and <a target="_blank" href="https://material.io/design/color/dark-theme.html">Android</a> team have implemented this feature. It's a good trend for users, but could bring designers and developers some challenges, including managing and naming the color sets, especially gray scale ones.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/material-dark.png" alt="Image" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://material.io/design/color/dark-theme.html">Material Design</a>'s dark theme guide</em></p>
<p>To think and communicate about gray scale colors dynamically, using terms like <em>white</em>, <em>light</em>, <em>black</em> or <em>dark</em> doesn't work. Because if we referred to a dynamic color <code>#000000</code> (black in HEX) <em>black</em> or <em>dark</em> in <code>light color scheme</code>, how do you talk about this particular color, which should turn into <code>#FFFFFF</code> (white in HEX), in <code>dark color scheme</code>? <em>defaultDark</em> or <em>lightDark</em>?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/color-transition.png" alt="Image" width="600" height="400" loading="lazy">
<em>Confusing transition of color sets</em></p>
<p>It is very confusing to name gray scale dynamic color sets in conventional approach. To avoid this confusion, we use <code>theme</code> and <code>contrast</code> to manage one set of color in <code>light</code> and <code>dark</code> schemes instead.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/airtable-color-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example color naming in demo <a target="_blank" href="https://airtable.com/shrHQdv9vQGz7UMQj">Airtable base</a></em></p>
<p>Note that a gray scale color doesn't always need to be reversed in opposite color mode. In these situations that light color remains light and dark remains dark, we simply name name it light or dark instead.</p>
<p>Once we wrap our head around this naming method, managing this architecture of color palette is easy in <code>Xcode</code>. To create a color set, simply create a new <code>Asset Catalog</code> file → add a new <code>Color Set</code> → and change <code>Appearances</code> to <code>Any, Light, Dark</code> will do.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/color-asset.png" alt="Image" width="600" height="400" loading="lazy">
<em>How to add color asset in Xcode</em></p>
<h3 id="heading-4-environment-settings">4. <code>environment</code> settings</h3>
<p>One awesome feature in SwiftUI framework is the <a target="_blank" href="https://developer.apple.com/documentation/swiftui/environment">environment modifier</a>, which provides ability to control <a target="_blank" href="https://developer.apple.com/documentation/swiftui/environmentvalues">environment values</a> on target view. In terms of building design system, this ability provides convenient approach to change app's font at root level. And the other advantage of using <code>environmentValue</code> is to change and test light and dark color schemes in development.</p>




<h3 id="heading-5-buttonstyle-and-button-label">5.  <code>buttonStyle</code> and button label</h3>
<p>Comparing to the old days in <a target="_blank" href="https://developer.apple.com/documentation/uikit">UIKit</a>, constructing reusable buttons in SwiftUI is drastically easier. The <a target="_blank" href="https://developer.apple.com/documentation/swiftui/button">Button view</a> consists of two parts, which are <code>action</code> closure (event to be fired as button is pressed) and <code>label</code> (body of the button). The view can then be chained with a modifier <code>buttonStyle</code>. To learn details about building reusable buttons,I recommend reading <a target="_blank" href="https://alejandromp.com/blog/2019/06/22/swiftui-reusable-button-style/">Alejandro's tutorial</a>, which is comprehensive and useful.</p>
<p>In our customized button components, first step is to create two structs, including <code>TokenButtonLabel</code> and <code>TokenButtonStyle</code>. These two structs are programmed according to the types of buttons we have in design files. For example, there're only two types of labels: icon and text. Each type has an according <code>init</code> function designed with different parameters for new instances.</p>


<p>On the other hand, there're four major types of button styles: circle icon, icon, capsule and text. To follow <code>ButtonStyle</code> protocol, a <code>makeBody</code> func has to be implemented. This function brings us a <code>configuration</code> property, providing a native <code>isPressed</code> value to monitor if the button is pressed or not.</p>


<p>Finally, stacking on top of <code>TokenButtonLabel</code> and <code>TokenButtonStyle</code>, the endpoint of the button component API will be <code>TokenButton</code> - a grouping that wraps content and style of button together, conforming to the button types in visual design system.</p>




<h3 id="heading-6-anyview-as-wrapper">6. <code>AnyView</code> as wrapper</h3>
<p>As we're dealing with the <code>makeBody</code> function brought by <code>ButtonStyle</code> protocol, we found a useful tip to work with <code>View</code>. To store a view in a variable, the type annotation could be indicated as <code>AnyView</code>, which works as a general container of views in SwiftUI.</p>
<p>In our case, because we want to add the opacity modifier to <code>configuration.label</code> to all types of buttons, instead of doing so repeatedly in each <code>switch</code> case, it makes more sense to chain the modifier at the end altogether. We can achieve this pattern by using the advantage of <code>AnyView</code> in this way:</p>




<h3 id="heading-7-build-view-modifier-with-mutating-function">7. Build view modifier with <code>mutating</code> function</h3>
<p>To update styles of the buttons dynamically, we can build our own modifier. First instantiate customized mutable state properties in view, and then create a <code>mutating</code> function which returns a <code>Self</code> type after updating the target state property.</p>




<h3 id="heading-8-tricky-border-style">8. Tricky border style</h3>
<p>One drawback of SwiftUI is styling a circle shape with circular border is not straightforward at all. I struggled for a while, and finally found a <a target="_blank" href="https://stackoverflow.com/questions/57269651/add-a-border-with-cornerradius-to-an-image-in-swiftui-xcode-beta-5">solution here on StackOverflow</a>. A <code>clipShape</code> and an <code>overlay</code> modifier are required to make it work.</p>




<hr>
<h2 id="heading-conclusion">Conclusion</h2>
<p>SwiftUI is an incredible improvement Apple makes. Though flaws still exist, building a robust and flexible design system with it, and furthermore complicated UI in iOS is way efficient than ever. I hope this article is helpful for any iOS team trying to build UI, and always welcome to any feedbacks!</p>
<p>? Read more of my works at <a target="_blank" href="https://www.vinceshao.com">vinceshao.com</a> / Follow me on <a target="_blank" href="https://twitter.com/vincemingpushao">Twitter</a> or <a target="_blank" href="https://www.linkedin.com/in/vinceshao/">LinkedIn</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
