<?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" version="2.0"><channel><title><![CDATA[Swift Matters]]></title><description><![CDATA[Where we discuss Swift matters... 

A little about me - I think in Swift ⚡️  iOS Developer 👨🏾‍💻 Cape Town South Africa 🏖]]></description><link>https://blog.malcolmk.com</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 18:01:26 GMT</lastBuildDate><atom:link href="https://blog.malcolmk.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Simplifying Swift Data Conversion]]></title><description><![CDATA[Data transformation, a common task for iOS engineers, arises in various forms throughout one's career. Whether it's translating an API response into a model object or adapting a model object for display purposes, the process of conversion is inevitab...]]></description><link>https://blog.malcolmk.com/simplifying-swift-data-conversion</link><guid isPermaLink="true">https://blog.malcolmk.com/simplifying-swift-data-conversion</guid><category><![CDATA[Swift]]></category><category><![CDATA[Xcode]]></category><category><![CDATA[ios app development]]></category><category><![CDATA[iOS]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Malcolm]]></dc:creator><pubDate>Tue, 05 Sep 2023 09:02:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1693903637939/3178fb72-b9b1-4bb6-8947-5a0e2ff1d7ca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Data transformation, a common task for iOS engineers, arises in various forms throughout one's career. Whether it's translating an API response into a model object or adapting a model object for display purposes, the process of conversion is inevitable. Yet, amidst this array of scenarios, how do you determine the most suitable approach for your project? In this article, we'll delve into two prominent methods: <strong>Protocol Conformance</strong> and <strong>Mapping Functions</strong>.</p>
<p>In essence, it all comes down to one word: flexibility. So, Protocol Conformance or Mapping Functions? Well, as you'll soon discover.</p>
<p>**<em>TDLR; It depends...😉</em></p>
<p>Imagine you have a set of custom data types representing different types of products in an e-commerce application. Each product type has its own set of properties and behaviors specific to that product. Here's a simplified example of two product types:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Book</span> </span>{
    <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> author: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">Double</span>
    <span class="hljs-comment">// Other book-specific properties and methods</span>
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Electronics</span> </span>{
    <span class="hljs-keyword">let</span> name: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> brand: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">Double</span>
    <span class="hljs-comment">// Other electronics-specific properties and methods</span>
}
</code></pre>
<p>Now, you want to display a list of these products in the same <code>UITableView</code> , <code>UICollectionView</code> or a SwiftUI list, and you also want to allow users to add these products to their shopping cart. How would you go about achieving this?</p>
<h2 id="heading-protocol-conformance">Protocol Conformance</h2>
<blockquote>
<p>"A <em>protocol</em> defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be <em>adopted</em> by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to <em>conform</em> to that protocol." - <a target="_blank" href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols/">The Swift Programming Language</a></p>
</blockquote>
<p>To go about this using protocol conformance one would first start by defining a protocol. Let's call it <code>ProductConvertible</code>.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">ProductConvertible</span> </span>{
    <span class="hljs-keyword">var</span> title: <span class="hljs-type">String</span> { <span class="hljs-keyword">get</span> }
    <span class="hljs-keyword">var</span> price: <span class="hljs-type">Double</span> { <span class="hljs-keyword">get</span> }
}
</code></pre>
<p>Then, you would have your <code>Book</code> and <code>Electronics</code> types conform to this protocol:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Book</span>: <span class="hljs-title">ProductConvertible</span> </span>{
    <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> author: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">Double</span>
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Electronics</span>: <span class="hljs-title">ProductConvertible</span> </span>{
    <span class="hljs-keyword">let</span> name: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> brand: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">Double</span>
}
</code></pre>
<p>You can then go ahead and create a <code>ViewModel</code> for the view that will display the products or use <code>ProductConvertible</code> directly.</p>
<h3 id="heading-pros">Pros</h3>
<p><strong>Polymorphism -</strong> When you have a protocol like <code>ProductConvertible</code>, you establish a shared contract that multiple types can conform to. This allows you to treat all conforming types uniformly, providing a consistent interface for working with different data models. In the case of a <code>list</code> or <code>UITableView</code>, you can use a single data source or delegate to handle various model types effortlessly.</p>
<p><code>let products: [ProductConvertible] = [book, electronics]</code></p>
<p><strong>Code Reusability</strong> - You can create generic functions and components that work with any type conforming to the protocol.</p>
<p><code>func displayProducts(_ products: [ProductConvertible])</code></p>
<p><strong>Ease of Extension -</strong> When new types need to be displayed in the list or UITableView, you can simply make them conform to the existing protocol.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Clothing</span>: <span class="hljs-title">ProductConvertible</span> </span>{
    <span class="hljs-keyword">let</span> name: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> brand: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">Double</span>
}
</code></pre>
<h3 id="heading-cons">Cons</h3>
<p><strong>Tight Coupling</strong> - Types conforming to a protocol become tightly coupled to the protocol's requirements. Any changes to the protocol can potentially affect all conforming types.</p>
<p><strong>Shared Protocol Requirements</strong> - When using protocol conformance, you need to ensure that the protocol requirements make sense for all conforming types. If some requirements are irrelevant for certain types, you may end up with unused methods or properties in your types. This can lead to unnecessary complexity. Our clean architecture coders out there will recognize this as a violation of the interface-segregation principle.</p>
<h2 id="heading-mapping-functions">Mapping Functions</h2>
<blockquote>
<p>Data mapping is the process of matching fields between two different data sets. It is a crucial step when combining data, since different data sources could have different styles, formatting, or names for the same kinds of data. - <a target="_blank" href="https://funnel.io/blog/your-guide-to-data-mapping#:~:text=Data%20mapping%20is%20the%20process,the%20same%20kinds%20of%20data.">Sean Dougherty</a></p>
</blockquote>
<p>In simple terms, a mapping function is a pure function that takes one type of data (the source) and converts it into another type of data (the target). Mapping functions are characterized by their functional purity, which means they produce the same output for the same input and have no side effects. (<code>func(A) -&gt; B</code>)</p>
<h3 id="heading-pros-1">Pros</h3>
<p><strong>Modularization</strong> - Using mapping functions, you can encapsulate the transformation logic in separate functions or a dedicated mapper class, promoting modularization and clean code.</p>
<p>Let's add a <code>ProductViewModel</code> that can be used to display items in our list.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ProductViewModel</span> </span>{
    <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> description: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> price: <span class="hljs-type">String</span>
}
</code></pre>
<p>We can then introduce a <code>ProductMapper</code> which can be used to transform/map our initial model items to the desired <code>ProductViewModel</code>.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">ProductMapper</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">mapBookToViewModel</span><span class="hljs-params">(<span class="hljs-number">_</span> book: Book)</span></span> -&gt; <span class="hljs-type">ProductViewModel</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">ProductViewModel</span>(
            title: book.title,
            description: <span class="hljs-string">"Author: \(book.author)"</span>,
            price: <span class="hljs-string">"$\(book.price)"</span>
        )
    }

    <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">mapElectronicsToViewModel</span><span class="hljs-params">(<span class="hljs-number">_</span> electronics: Electronics)</span></span> -&gt; <span class="hljs-type">ProductViewModel</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">ProductViewModel</span>(
            title: electronics.name,
            description: <span class="hljs-string">"Brand: \(electronics.brand)"</span>,
            price: <span class="hljs-string">"$\(electronics.price)"</span>
        )
    }
}
</code></pre>
<p>Now our mapping logic is encapsulated in a separate object with separate functions that can live in isolation.</p>
<p><strong>Testing -</strong> Mapping functions can be easily unit-tested to ensure they correctly transform data from one type to another. This can be challenging with protocol conformance, especially if the protocol involves complex behavior. It is good practice to make mapping functions static.</p>
<p><strong>Code Reusability -</strong> Mapping functions can be reused across different parts of your application. For example, you might need to convert your custom types to different standardized representations for different use cases. A single mapping function can serve multiple purposes. This is not possible when using protocol conformance as you can only have one conformance to a protocol.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BookMapper</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">mapBookToViewModel</span><span class="hljs-params">(<span class="hljs-number">_</span> book: Book)</span></span> -&gt; <span class="hljs-type">ProductViewModel</span> {
        <span class="hljs-type">ProductViewModel</span>(
            title: book.title,
            author: book.author,
            price: <span class="hljs-string">"$\(book.price)"</span>
        )
    }

    <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">mapDiscountedBookToViewModel</span><span class="hljs-params">(<span class="hljs-number">_</span> book: Book,
                                             discountPercentage: Double)</span></span> -&gt; <span class="hljs-type">ProductViewModel</span> {
        <span class="hljs-keyword">let</span> discountedPrice = book.price * (<span class="hljs-number">1.0</span> - discountPercentage / <span class="hljs-number">100.0</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-type">ProductViewModel</span>(
            title: book.title,
            author: book.author,
            price: <span class="hljs-string">"$\(discountedPrice)"</span>
        )
    }
}
</code></pre>
<p>We now have two different conversions on the same model but our mapping functions give us extra functionality.</p>
<p><strong>Flexibility</strong> - If you introduce a new type, such as <code>Clothing</code>, you can easily create a new mapping function without modifying existing code.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Clothing</span> </span>{ <span class="hljs-comment">/* ... */</span> }

<span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">mapClothingToViewModel</span><span class="hljs-params">(<span class="hljs-number">_</span> clothing: Clothing)</span></span> -&gt; <span class="hljs-type">ProductViewModel</span> {
    <span class="hljs-comment">// Transformation logic here</span>
}
</code></pre>
<p><strong>Performance</strong> - In some cases, mapping functions can be more performant than protocol conformance, especially if the mapping involves complex calculations or data manipulation. You have more control over when and how the mapping occurs.</p>
<p>Let's say we need to perform complex calculations when mapping our models we can use caching and memoization to store the results of specific inputs and prevent unnecessary recalculations. We could also perform these operations over multiple threads in parallel.</p>
<p>This is not possible with protocol conformance as in Swift, when objects conform to a protocol, the conformance often involves an eager transformation. This means that the transformation logic specified in the protocol's methods is executed when the object is created or when the protocol methods are invoked.</p>
<p><a target="_blank" href="https://medium.com/geekculture/the-surprising-cost-of-protocol-conformances-in-swift-dfa5db15ac0c">For more on the performance of protocol conformance...</a></p>
<p><strong>Loose Coupling</strong> - When you use a mapping function, the mapping logic is external to your types. Changes to your types won't directly impact the mapping function, and vice versa. However, if you introduce a new type that needs to be mapped to the target representation (<code>ProductCellViewModel</code> ), you will need to create a new mapping function for that type. While this does couple the mapping function to the new type, it doesn't necessarily affect the existing types.</p>
<p>In both cases, there is a level of coupling, but the key difference is where that coupling occurs:</p>
<ul>
<li><p>With <strong><em>protocol conformance</em></strong>, the coupling is within the types themselves. Changes to the protocol can affect all conforming types.</p>
</li>
<li><p>With a <strong><em>mapping function</em></strong>, the coupling occurs when you create a new mapping function for a specific type. Existing types don't need to change when a new type is introduced.</p>
</li>
</ul>
<h3 id="heading-cons-1">Cons</h3>
<p><strong>Mapping Calls</strong> - You need to explicitly call the mapping functions when populating the list, which can lead to additional code for type checks and mappings.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> productViewModel: <span class="hljs-type">ProductViewModel</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> book = product <span class="hljs-keyword">as</span>? <span class="hljs-type">Book</span> {
    productViewModel = <span class="hljs-type">ProductMapper</span>.mapBookToViewModel(book)
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> electronics = product <span class="hljs-keyword">as</span>? <span class="hljs-type">Electronics</span> {
    productViewModel = <span class="hljs-type">ProductMapper</span>.mapElectronicsToViewModel(electronics)
}
</code></pre>
<p><strong>Boilerplate Code</strong> - Mapping functions can introduce unnecessary boilerplate code, especially in the case of simple one-to-one mappings. In such cases, protocol conformance would be better suited. Could also be seen as an unneeded abstraction layer by some.</p>
<p><strong>Code Duplication</strong> - This can lead to code duplication if similar mapping logic is implemented in multiple places. This can make it harder to maintain consistency and make updates.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>It's essential to carefully assess your specific project requirements and consider the trade-offs when deciding whether to use mapping functions or other approaches like protocol conformance or direct property mapping. Mapping functions can be a powerful tool for complex data transformations, but they should be used with good judgment to avoid introducing unnecessary complexity into your codebase.</p>
<h1 id="heading-next-time">Next time...</h1>
<p>Now that we've examined various methods of data transformation, a new challenge emerges. Consider this scenario: You want to trigger different actions when an item in our list is tapped. Have you ever grappled with the casting pyramid of doom?</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, didSelectRowAt indexPath: IndexPath)</span></span> {
    <span class="hljs-keyword">let</span> selectedProduct = products[indexPath.row]
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> book = selectedProduct <span class="hljs-keyword">as</span>? <span class="hljs-type">Book</span> {
        <span class="hljs-comment">// Perform action for Book</span>
        performActionForBook(book)
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> electronics = selectedProduct <span class="hljs-keyword">as</span>? <span class="hljs-type">Electronics</span> {
        <span class="hljs-comment">// Perform action for Electronics</span>
        performActionForElectronics(electronics)
    }
}
</code></pre>
<p>But what happens when we introduce more types? Do we simply keep adding more <code>if let</code> statements? There must be a more elegant solution. That's precisely what we'll delve into in our next post!</p>
<p>Thank you for reading. If you found this article insightful, please consider leaving a like and sharing it. 👏🏾🚀</p>
]]></content:encoded></item><item><title><![CDATA[Kotlin Multiplatform Mobile - An iOS Engineer's Hot Take]]></title><description><![CDATA[In this article, I will be discussing why I believe that Kotlin Multiplatform Mobile (KMM) is the future of cross-platform development from the viewpoint of an iOS Engineer. 
This is a highly opinionated piece and I am very aware that some might have...]]></description><link>https://blog.malcolmk.com/kotlin-multiplatform-mobile-an-ios-engineers-hot-take</link><guid isPermaLink="true">https://blog.malcolmk.com/kotlin-multiplatform-mobile-an-ios-engineers-hot-take</guid><category><![CDATA[Swift]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Android]]></category><dc:creator><![CDATA[Malcolm]]></dc:creator><pubDate>Fri, 30 Jul 2021 11:01:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627544447858/SrcT7BsyY.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I will be discussing why I believe that Kotlin Multiplatform Mobile <em>(KMM)</em> is the future of cross-platform development from the viewpoint of an iOS Engineer. </p>
<p>This is a highly opinionated piece and I am very aware that some might have opposing opinions hence - hot take. </p>
<blockquote>
<p>Hot Take (noun) - a piece of writing or speech, especially on the internet, giving someone's personal opinions about a topic, usually strong opinions that have not been carefully thought about and that many people are likely to disagree with 
<a target="_blank" href="https://dictionary.cambridge.org/dictionary/english/hot-take">Cambridge Dictionary</a> </p>
</blockquote>
<h1 id="lets-talk-about-cross-platform-development">Let's talk about cross-platform development</h1>
<p>Have you ever downloaded an app, opened it, browsed through it, and think something just does not feel right? Ever wondered why an app is not smooth and why some elements seem out of place? It could be that the app in question was developed using a cross-platform framework. </p>
<p>The promise of cross-platform development is "code once, deploy everywhere". Whilst frameworks like React-Native and Flutter do really well to deliver on this promise there are some caveats that raise concern. User Interface and latest platform features is an area in which I feel like these frameworks fall short. In practice, this may not be the fault of the framework but rather that of the engineer not taking the time to ensure that the final result conforms to specific platform standards. </p>
<p>To make a good cross-platform application one has to be conscious of platform differences and cater to them. iOS has its Human Interface Guidelines and Android has Material Design. For your app to feel at home on a device it is crucial that you adhere to the platform principles. </p>
<p>This leads to one have to write code for each platform somewhat creating a nuisance in the development process. "I was promised write once, deploy everywhere. But to make it look nice and work properly I still have to code twice?" Eventually, you could end up in the not ideal situation of having a codebase that has so many <em>if</em> or <em>switch</em> statements to cater for platform-specific code. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627633315818/vRdBa84mG.png" alt="image.png" /></p>
<h1 id="kotlin-multiplatform-mobile-what-is-it">Kotlin Multiplatform Mobile - What is it?</h1>
<blockquote>
<p>Kotlin Multiplatform Mobile allows you to use a single codebase for the business logic of iOS and Android apps. You only need to write platform-specific code where it’s necessary, for example, to implement a native UI or when working with platform-specific APIs. -  <a target="_blank" href="https://kotlinlang.org/lp/mobile/">Kotlin.org</a> </p>
</blockquote>
<p>KMM is a relatively new framework <em>(Alpha released Aug. 2020)</em> to the cross-platform world that enables you to share common code between your Android and iOS Applications. This is done by creating a shared module written in Kotlin that is then compiled to bytecode and native iOS. </p>
<p>Unlike other cross-platform frameworks, KMM gives you the choice to decide what aspects of your code you want to share. You can decide to share as little code as possible or do the opposite. The shared code module can be included in existing projects using  <a target="_blank" href="https://kotlinlang.org/docs/native-cocoapods.html#use-a-kotlin-gradle-project-as-a-cocoapods-dependency">Cocoapods</a>  and  <a target="_blank" href="https://johnoreilly.dev/posts/kotlinmultiplatform-swift-package/">SPM</a>.</p>
<p>KMM does not currently have a UI component this allows you to keep your UI native. No need to learn a new language for UI. You also get the benefit of being able to use all the latest platform features like SwiftUI and JetPack Compose. </p>
<p>I must say that I have been thoroughly impressed with the documentation and resources the JetBrains team has been creating for KMM. Take a look at the  <a target="_blank" href="https://youtube.com/playlist?list=PLlFc5cFwUnmy_oVc9YQzjasSNoAk4hk_C">Youtube Channel</a>  and the  <a target="_blank" href="https://kotlinlang.org/docs/mobile/home.html">official documentation</a>  for yourself. ⭐️</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627633274452/tC5h3-k-tH.png" alt="image.png" /></p>
<h2 id="my-key-takeaways">My Key takeaways</h2>
<ul>
<li><strong><em>Flexibility</em></strong>, only share the code you want to share.</li>
<li><strong><em>Compiled to bytecode</em></strong>, does not increase binary size like other cross-platform frameworks.</li>
<li><strong><em>Native UI</em></strong>, you can use UIKit and SwiftUI. </li>
</ul>
<h1 id="common-ios-engineer-questions">Common iOS Engineer questions</h1>
<p><strong><em>1. Do I have to learn Kotlin?</em></strong></p>
<p>Yes. To contribute to the shared code module you will have to learn some Kotlin. This might be a big learning curve but most of the things we as iOS Engineers love about Swift are also true for Kotlin. Type-safety, optionals, and clean syntax are all present in Kotlin. </p>
<p><strong><em>2. Will I have to code in Android Studio? </em></strong></p>
<p>Yes. No. Probably. To be a contributor on the app's shared code you will probably have to use Android studio but for all other native code, you can still use Xcode.</p>
<p><strong><em>3. How will I debug Kotlin code? </em></strong></p>
<p>With Android Studio. </p>
<p><strong><em>4. Libraries, Cocoapods, and Swift Packages? </em></strong></p>
<p>You can use libraries, Cocoapods, and packages as normal in your iOS project. </p>
<p><strong><em>5. How does KMM handle concurrency? </em></strong></p>
<p>Using Kotlin/Native. Please read  <a target="_blank" href="https://blog.jetbrains.com/kotlin/2020/07/kotlin-native-memory-management-roadmap/">this post</a> from JetBrains on Kotlin/Native Memory Management Roadmap for a more detailed explanation. </p>
<p>More questions? See the Frequently Asked Questions page on  <a target="_blank" href="https://kotlinlang.org/docs/mobile/faq.html">Kotlin.org</a> </p>
<h1 id="the-cons">The Cons</h1>
<p>Now let's be honest there is no such thing as a silver bullet for cross-platform development. Let's take a look at the cons: </p>
<p><strong>1. No shared UI </strong></p>
<p>While some may see this as a con I on the other hand see it like a pro. I don't want to have a shared UI. I would rather have two targets one in SwiftUI and the other in Jetpack Compose. KMM does not currently provide a way to have shared UI components. I hope they keep it this way so that apps can maintain their native feel. If you do want to have shared UI components then ReactNative or Flutter is best suited. </p>
<p><strong>2. Production readiness </strong></p>
<p>KMM is a fairly new player to the cross-platform world and is still considered to be in development. Some features are still in the alpha/experimental phase of development. I don't think that this is cause for alarm to not use it. There are teams from  <a target="_blank" href="https://kotlinlang.org/lp/mobile/case-studies/">Netflix and CashApp</a>  already using KMM in production. The development team is very good at communicating the stability of components and there's a dedicated  <a target="_blank" href="https://kotlinlang.org/docs/components-stability.html">page for this</a>.</p>
<p><strong>3. New build tools</strong></p>
<p>As an iOS developer, I have become accustomed to Xcode and its quirks like having to clear derived data religiously. Having to learn how to use Android Studio and Gradle will be a major hurdle. Shared code needs to be debugged in Android Studio. For an iOS Engineer, you will now need two IDEs to develop whilst Android Engineers can achieve everything from Android Studio. I think the new tools will be the biggest challenge for an iOS developer. </p>
<p><strong>4. Networking</strong></p>
<p>While there is support for networking using the Ktor library development for networking with  <a target="_blank" href="https://www.apollographql.com/docs/android/essentials/get-started-multiplatform/">GraphQL</a>  is still in the experimental phase. I could not find any solutions for  <a target="_blank" href="https://github.com/grpc/grpc-kotlin/issues/51">networking with gRPC</a>. These limitations write off KMM for teams that use these technologies. </p>
<p><strong>4. Complexity</strong></p>
<p>Introducing KMM or any cross-platform framework introduces complexity to app development. There are more aspects involved in the development life cycle. KMM is still in its infancy there will definitely be some pains experienced. With the community still being small there might not be enough resources online to help resolve some of the issues one might run into. </p>
<p>With that said if introducing KMM to a team that already has experienced Android Engineers, I'm sure the learning curve will be accelerated as they can assist you with any errors you may encounter with Android studio or Gradle.</p>
<p>I know the chances of this happening are close to impossible but it would be really awesome if Xcode had a KMM plugin. </p>
<p>There are some other downsides to using KMM for app development but in the spirit of keeping this post short and concise, we won't discuss them. I have included a list of resources that go into detail about some of the other cons like ObjC-interoperability, memory handling, and multi-threading below.  </p>
<h1 id="an-argument-for-shared-code">An argument for shared code</h1>
<p><strong>Scenario:</strong> <em>You work on a team with dedicated iOS and Android teams. You're working on a new feature. The feature's business logic is designed and ready for development. Both teams go their separate ways and code the feature. Time for testing comes and QA reports that the feature works fine on Android but there is something wrong on iOS or vice-versa. </em></p>
<p>This is a situation many have been in. Having a shared codebase may be the solution to the situation above. Having a single source of truth for an application's business logic introduces predictability and stability. </p>
<h1 id="conclusion">Conclusion</h1>
<p>My favorite aspect about Kotlin Multiplatform Mobile is its flexibility. You only have to share what you decide to share. Rather than UI components being bridged, they remain native. Code is compiled to bytecode. </p>
<p>These reasons are why I think KMM should be welcomed by the iOS community. It creates an environment for collaboration between communities and introduces the challenge of learning a new language and tools. 🤖 🤝🍏</p>
<p>I develop to solve problems that help people. The people that download our apps usually don't care about the technology used to make the app. What users want are good products and if KMM provides teams a way to deliver earlier then it's a win. 🚀</p>
<p>I'm looking forward to all the new features in KMM and the growth of this community. 
Thanks for reading my hot take on why I as an iOS Engineer like KMM! What's your opinion on Kotlin Multiplatform Mobile? </p>
<h2 id="resources">Resources</h2>
<ol>
<li><a target="_blank" href="https://kotlinlang.org/docs/mobile/home.html">Kotlin Multiplatform Documentation</a>  </li>
<li><a target="_blank" href="https://medium.com/icerock/the-dos-and-donts-of-mobile-development-with-kotlin-multiplatform-db7c098545c0">The Dos and Dont's of Mobile Development with Kotlin Multiplatform</a> </li>
<li><a target="_blank" href="https://www.luminis.eu/blog/development-en/kotlin-multiplatform-a-remedy-for-all-mobile-app-development/">Kotlin Multiplatform – A remedy for all mobile app development?</a> </li>
<li><a target="_blank" href="https://proandroiddev.com/kotlin-multiplatform-a-panacea-for-mobile-app-development-c41ffe850d1b">Kotlin Multiplatform — A panacea for mobile app development?</a> </li>
<li><a target="_blank" href="https://medium.com/kodein-koders/we-asked-an-ios-developer-his-thoughts-after-working-with-kotlin-multiplatform-mobile-b08b8750be33">We asked an iOS developer his thoughts after working with Kotlin/Multiplatform Mobile</a> </li>
</ol>
]]></content:encoded></item><item><title><![CDATA[My iOS TechStack 2021]]></title><description><![CDATA[In this post, I'll share the tools, architecture, and resources I'm currently using to develop.
A little about me: I'm an iOS engineer in Cape Town, South Africa 🏝👋🏾. I have been developing iOS applications for over 5 years now in FinTech and E-co...]]></description><link>https://blog.malcolmk.com/my-ios-techstack-2021</link><guid isPermaLink="true">https://blog.malcolmk.com/my-ios-techstack-2021</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[Xcode]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Malcolm]]></dc:creator><pubDate>Tue, 06 Jul 2021 08:17:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1625551651959/mm3eIlenV.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, I'll share the tools, architecture, and resources I'm currently using to develop.</p>
<p>A little about me: I'm an iOS engineer in Cape Town, South Africa 🏝👋🏾. I have been developing iOS applications for over 5 years now in FinTech and E-commerce. I love building products that impact people's lives and I think in Swift ⚡️😉.</p>
<p>My aim to make this an annual inclusion on my blog. This list will summarize my learnings each year and a way to share new things. It will be interesting to see how this list changes from year to year. </p>
<h1 id="ios-development-in-2021">iOS Development in 2021</h1>
<p>It is a very exciting time to be an iOS developer. #WWDC21 &amp; #WWDC20 were full of so many new and interesting things which we can now use to build applications. Whilst some can not be used immediately due to lack of backward compatibility with iOS versions I see this as an opportunity to learn. Between now and the time your team is ready to drop support for previous iOS versions you can use the time to learn things like SwiftUI, Combine, and async-await. </p>
<p><em>Since most of the apps I work on can't use some of these latest features Apple has released you will not see them included in the list.</em></p>
<h1 id="tldr-too-long-didnt-read">TL;DR (Too long; didn't read)</h1>
<ul>
<li>Fastlane</li>
<li>GitHub</li>
<li>CI / CD - GitHub Actions</li>
<li>SwiftLint</li>
<li>SwiftGen</li>
<li>RxSwift</li>
<li>MVVM</li>
<li>UIKit </li>
<li>Quick &amp; Nimble</li>
<li>Blogs </li>
<li>YouTube</li>
</ul>
<h1 id="dev-tools">Dev Tools</h1>
<p>These are the tools that I make use of for CI <em>(Continuous Integration)</em> &amp; CD <em>(Continuous Delivery)</em></p>
<ul>
<li>Xcode</li>
</ul>
<p>It's close to impossible if not impossible to be an iOS Developer and not use Xcode. Our beloved IDE has improved drastically over the years. The team at Apple has released many awesome features to make our lives as developers easier. Personally, I really love the source control integrations and can't wait to try out Xcode Cloud. </p>
<ul>
<li><a target="_blank" href="https://fastlane.tools/">Fastlane</a> </li>
</ul>
<p>I use Fastlane to automate <em>everything</em>! Releases, release notes, changelogs, TestFlight and AppStore builds are amongst some of the things that I automate with Fastlane. </p>
<ul>
<li>GitHub</li>
</ul>
<p>Not only do I use Github for source control but also have recently started using GitHub Actions for CI/CD. Having my code and CI/CD in one location is a major win for me 💯. </p>
<h1 id="code-tools">Code Tools</h1>
<ul>
<li>SwiftLint &amp; SwiftGen</li>
</ul>
<p>Every iOS project in my opinion should have these tools set up.  <a target="_blank" href="https://github.com/SwiftGen/SwiftGen">SwiftLint</a>  ensures that code style and syntax are adhered to and consistent.  <a target="_blank" href="https://github.com/realm/SwiftLint">SwiftGen</a> generates code for all your resources to make them type-safe. All iOS Developers love type-safety and clean code ❤️.</p>
<ul>
<li>Swift Package Manager &amp; CocoaPods </li>
</ul>
<p>I have started moving libraries from CocoaPods and using SPM for dependency management as more libraries add support for it. </p>
<h1 id="architecture">Architecture</h1>
<p>The topic of architecture and design patterns will always be a hot topic for the iOS community. I would like to believe I have found an architecture that works for <strong>me</strong>. This section could possibly be a series of posts on its own. </p>
<ul>
<li>MVVM <em>(Model-View-ViewModel)</em></li>
<li>RxSwift</li>
<li><a target="_blank" href="https://www.hackingwithswift.com/articles/71/how-to-use-the-coordinator-pattern-in-ios-apps">Coordinator pattern</a> </li>
<li><a target="_blank" href="https://github.com/stephencelis/SQLite.swift">SQLite</a> for persistence</li>
<li><a target="_blank" href="https://github.com/grpc/grpc-swift">gRPC</a> </li>
<li><a target="_blank" href="https://github.com/Quick/Nimble">Quick &amp; Nimble</a> for unit tests</li>
</ul>
<p>I am very fond of the MVVM pattern. It does not have too much boilerplate code which makes it clear to understand and is testable. In tandem with MVVM I like to use RxSwift for binding properties to views. Apple has endorsed <a target="_blank" href="https://yalantis.com/blog/reactive-programming-on-objective-c/">Function Reactive Programming</a>  with Combine. I look forward to when I can replace RxSwift with Combine in the future. </p>
<p>I have included gRPC even though this is usually dependent on the backend. Working with gRPC is such a delight. I don't know why more teams do not use gRPC. It is lightweight, type-safe, and has built-in code generation for most languages. You can read more  <a target="_blank" href="https://www.altexsoft.com/blog/what-is-grpc/">here</a>.  </p>
<p>#UI</p>
<p>I won't go too much into detail here but will include links to resources that discuss the topics listed. Leave a comment if you'd like me to write on any of the topics more in detail and discuss my specific implementations. </p>
<ul>
<li><a target="_blank" href="https://stackoverflow.com/questions/61162934/generic-uiview-initializer-with-closure-in-swift">Styleable views</a></li>
</ul>
<ul>
<li><p><a target="_blank" href="https://swiftwithmajid.com/2019/01/17/using-protocols-as-composable-extensions/">Composable &amp; Reusable protocols</a> </p>
</li>
<li><p><a target="_blank" href="https://www.raywenderlich.com/2198310-uistackview-tutorial-for-ios-introducing-stack-views">StackViews</a>  </p>
</li>
<li><p><a target="_blank" href="http://octotap.com/2019/08/03/uistackview-inside-uiscrollview/">ScrollStackViewControllers</a> </p>
</li>
<li><p><a target="_blank" href="https://lickability.com/blog/getting-started-with-uicollectionviewcompositionallayout/">Compositional Layout</a> </p>
</li>
<li><p><a target="_blank" href="https://github.com/ra1028/DiffableDataSources">DiffableDatasource</a> </p>
</li>
<li><p><a target="_blank" href="https://github.com/onevcat/Kingfisher">KingFisher</a> </p>
</li>
</ul>
<p>I have to mention these two libraries DiffableDataSource &amp; KingFisher 🌟. DiffableDataSource is a backport of Apple's diffable data source available to use from iOS 9 and above. So you can use compositional layouts and diffable data sources without dropping support for previous iOS versions.</p>
<p>KingFisher is the image cache king. If your app downloads images take a look at this library. It adds support for caching, loading states, placeholder images, and other image rendering-related features. </p>
<h1 id="knowledge-base">Knowledge Base</h1>
<p>It's important to always keep abreast with the latest technology and keep improving your skills. Below is a list of resources that I use to achieve this.</p>
<h2 id="community">Community</h2>
<ul>
<li>Github</li>
<li>Twitter</li>
<li>Colleagues</li>
<li>Stackoverflow</li>
</ul>
<p>The iOS developer community is such an awesome community. There are so many people freely sharing their knowledge with others. Over the years I have learned so much from this community. </p>
<p><em>How to best utilize the community: </em></p>
<ol>
<li>Be active! create a Twitter profile, follow other iOS developers, attend iOS Dev Happy hour.</li>
<li>Read docs, read code on Github, find public repos, try to understand the code. </li>
<li>Use Stackoverflow, don't just copy-paste, understand then copy-paste.</li>
<li>Learn from your colleagues and your seniors. Don't be afraid to ask questions and challenge the status quo. </li>
</ol>
<h2 id="blogs">Blogs</h2>
<ul>
<li><a target="_blank" href="https://www.swiftbysundell.com/">SwiftBySundell</a> </li>
<li><a target="_blank" href="https://www.hackingwithswift.com/">Hacking with Swift</a> </li>
<li><a target="_blank" href="https://swiftwithmajid.com/">SwiftWithMajid</a> </li>
<li><a target="_blank" href="https://onmyway133.com/">Swift Discovery by Khoa</a> </li>
<li><a target="_blank" href="https://www.avanderlee.com/">SwiftLee</a> </li>
<li><a target="_blank" href="https://lickability.com/">Lickability</a>  </li>
<li><a target="_blank" href="https://www.fivestars.blog/">FiveStars</a> </li>
<li><a target="_blank" href="https://www.vadimbulavin.com/">Vadim Bulavin</a> </li>
<li>Medium</li>
<li>Hashnode </li>
</ul>
<h2 id="youtube">YouTube</h2>
<ul>
<li><a target="_blank" href="https://www.youtube.com/c/tundsdev">TundsDev</a> </li>
<li><a target="_blank" href="https://www.youtube.com/c/Kavsoft/featured">KavSoft</a> </li>
<li><a target="_blank" href="https://www.youtube.com/user/freter42">Peter Friese</a> </li>
</ul>
<h2 id="books">Books</h2>
<ul>
<li><a target="_blank" href="https://www.donnywals.com/">Donny Wals</a> </li>
<li><a target="_blank" href="https://www.swiftjectivec.com/a-best-in-class-app/">Swiftjectivec</a> </li>
<li><a target="_blank" href="https://www.raywenderlich.com/">Raywenderlich</a> </li>
</ul>
<h2 id="newsletters">NewsLetters</h2>
<ul>
<li><a target="_blank" href="https://infinum.com/ios-cocoa-treats/">Infinum iOS Cocoa Treats</a> </li>
<li><a target="_blank" href="https://ios-goodies.com/">iOSGoodies</a> </li>
</ul>
<blockquote>
<p>"Be the senior engineer you needed as a junior." - Anon</p>
</blockquote>
<p>Thank you for reading my post, leave a comment with tools that you love ✌🏾.
Keep thinking in Swift ⚡️!</p>
]]></content:encoded></item><item><title><![CDATA[Swift Network Layer, Part 1: Designing The API]]></title><description><![CDATA[Welcome 👋 to part one of the Swift Network Layer Series where we will be laying the foundation for our network layer. 

Pre-requisites

Xcode 11
Basic understanding of Swift & Networking


API Design
Things I like to keep in mind when designing an A...]]></description><link>https://blog.malcolmk.com/swift-network-layer-part-1-designing-the-api</link><guid isPermaLink="true">https://blog.malcolmk.com/swift-network-layer-part-1-designing-the-api</guid><category><![CDATA[Swift]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Malcolm]]></dc:creator><pubDate>Thu, 10 Sep 2020 09:32:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1599715624802/Ik6AAflGQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome 👋 to part one of the Swift Network Layer Series where we will be laying the foundation for our network layer. </p>
<blockquote>
<p>Pre-requisites</p>
<ul>
<li>Xcode 11</li>
<li>Basic understanding of Swift &amp; Networking</li>
</ul>
</blockquote>
<h1 id="api-design">API Design</h1>
<p>Things I like to keep in mind when designing an API are syntax and style. Syntax defines whether the API is declarative (which defines the computational logic i.e the "<strong>what</strong>") or imperative (defines state changes i.e the "<strong>how</strong>") whereas style defines whether the design paradigm is <em>concrete</em> or <em>abstracted</em> with <em>generics</em> and <em>protocols</em>. </p>
<p>The goal of this network layer is to design an API that is easy to use whilst being powerful and easily customizable. To achieve this we need to set some requirements for the framework: </p>
<ul>
<li>Generic </li>
<li>Typesafe </li>
<li>Declarative </li>
<li>Single source of truth </li>
<li>Abstracts implementation details</li>
</ul>
<p>With the requirements set out what I usually do is dive straight in Xcode and try to imagine what using this framework would look like.</p>
<p>To start we’ll create a new Xcode project and add the following line to <code>ViewController.swift</code>. </p>
<pre><code><span class="hljs-keyword">let</span> publisher = client.request([<span class="hljs-type">User</span>].<span class="hljs-keyword">self</span>, from: .users)
</code></pre><p>With the line above we have set a clear goal for what we aim to achieve. One thing I love the most about Swift is the language "<strong>readability</strong>". When designing an API I aim to have it read like a normal English sentence. </p>
<p>Reading the above line of code:  "<strong>Client</strong> request list of <strong>User</strong> from <strong>users</strong>”. </p>
<p>Not exactly everyday language but it’s close enough to give an idea of what that line of code does without any prior knowledge of the implementation. </p>
<p>Let’s break down our initial line of code even further and look at each component </p>
<ul>
<li><strong>publisher</strong>: <em>hints to the use some publisher-subscriber pattern</em></li>
<li><strong>client</strong>: <em>is able to perform requests</em></li>
<li><strong>User</strong>:  <em>is some model representing a user</em></li>
<li><strong>.users</strong>: <em>is some enum encapsulating a resource from which Users can be requested</em></li>
</ul>
<p>The <strong>client</strong> is requesting a list of type <strong>User</strong> from users and the response will be published to the publisher. </p>
<p>Right now Xcode should be throwing a couple of errors. Xcode is unable to resolve what the <strong>client</strong> and User are. The next task is to get rid of the errors we currently have and make Xcode happy. This approach to development lends itself well to TDD (<em>Test Driven Development</em>). Whilst we won’t be writing unit tests in this section we will be following a similar pattern of <em>RED, GREEN, REFACTOR</em> found in <em>TDD</em>. I like to call this approach something more sinister like <strong>“Error Driven Development”</strong> 😅. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1599716894696/hyi9k5FSL.png" alt="Screenshot 2020-09-10 at 07.48.07.png" /></p>
<h1 id="code">Code</h1>
<h3 id="folder-structure">Folder Structure</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1599717007227/BZGqLB2b3.png" alt="image.png" /></p>
<h2 id="user">User</h2>
<p>For part one, we will be making use of the JSON Placeholder API. If you go to https://jsonplaceholder.typicode.com/users in your browser you will see a JSON response containing an array of users. Our User model will be a representation of this response. Add the code below to a file of your liking <code>Network.swift</code> or <code>ViewController.swift</code>. </p>
<ul>
<li>One error down, on to the next one 👉</li>
</ul>
<pre><code>struct User: Decodable {
    <span class="hljs-keyword">let</span> id: Int
    <span class="hljs-keyword">let</span> name: <span class="hljs-built_in">String</span>
    <span class="hljs-keyword">let</span> username: <span class="hljs-built_in">String</span>
    <span class="hljs-keyword">let</span> email: <span class="hljs-built_in">String</span> 
}
</code></pre><h2 id="client">Client</h2>
<p>The next error we have to address is the <em><code>unresolved identifier client</code></em>. In <code>Client.swift</code> add the following code </p>
<pre><code><span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Client</span> </span>{ }
</code></pre><p>Now where you declared your publisher above go ahead and create a new instance of <strong>Client</strong>. </p>
<pre><code><span class="hljs-keyword">let</span> client = <span class="hljs-type">Client</span>()
</code></pre><p>At this point, you should have the following error in Xcode: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1599717513239/adfR-puk0.png" alt="image.png" /></p>
<p>In understandable English, the first error thrown here is telling us that Xcode is unable to infer what we mean by <code>.users</code>. </p>
<p>The second error is easier to understand, there is no method named <strong>request</strong> on the client. </p>
<p>Let’s address the easier of the two errors by declaring our <strong>request</strong> method on the <strong>client</strong>. </p>
<h2 id="clienttype">ClientType</h2>
<p>In <code>Client.swift</code> add the following protocol and implementation: </p>
<pre><code><span class="hljs-keyword">import</span> Combine
<span class="hljs-keyword">import</span> Foundation

<span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">HTTPClient</span> </span>{
    <span class="hljs-keyword">associatedtype</span> <span class="hljs-type">Route</span>: <span class="hljs-type">RouteProvider</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">request</span>&lt;T: Decodable&gt;<span class="hljs-params">(<span class="hljs-number">_</span> model: T.<span class="hljs-keyword">Type</span>,
                               from route: Route,
                               urlSession: URLSession)</span></span> -&gt; <span class="hljs-type">AnyPublisher</span>&lt;<span class="hljs-type">HTTPResponse</span>&lt;<span class="hljs-type">T</span>&gt;, <span class="hljs-type">HTTPError</span>&gt;
}

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Client</span>&lt;<span class="hljs-title">Route</span>: <span class="hljs-title">RouteProvider</span>&gt;: <span class="hljs-title">HTTPClient</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">request</span>&lt;T&gt;<span class="hljs-params">(<span class="hljs-number">_</span> model: T.<span class="hljs-keyword">Type</span>,
                    from route: Route,
                    urlSession: URLSession = .shared)</span></span> -&gt; <span class="hljs-type">AnyPublisher</span>&lt;<span class="hljs-type">HTTPResponse</span>&lt;<span class="hljs-type">T</span>&gt;, <span class="hljs-type">HTTPError</span>&gt; {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"Not implemented yet"</span>)
    }

}
</code></pre><p>We declare a <strong>HTTPClient</strong> protocol which will serve as the blueprint for our client. First, we provide the protocol with an <em>associatedtype</em> of <strong>RouteProvider</strong>. </p>
<blockquote>
<p> <a target="_blank" href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html#:~:text=An%20associated%20type%20gives%20a,specified%20with%20the%20associatedtype%20keyword.">… An associated type gives a placeholder name to a type that is used as part of the protocol. The actual type to use for that associated type isn’t specified until the protocol is adopted. Associated types are specified with the <em>associatedtype</em> keyword.</a>  </p>
</blockquote>
<p>Declare the request function which takes in a model parameter that will represent the response object we want to decode from the request. The route parameter will represent the HTTP route to fetch the expected response object. The last argument is the <em>URLSession</em> which will allow us to pass in a <em>URLSession</em> to use with the request. The function returns a publisher with a generic <strong>HTTPResponse</strong> on our model object and an <strong>HTTPError</strong>. </p>
<p>Create the Client class which will implement the <strong>HTTPClient</strong> protocol. For now, we will leave the implementation empty. I’ve added a <em>fatalError</em> message to ensure that we get back to it. In the code above we made <strong>RouteProvider</strong>, <strong>HTTPResponse</strong>, and <strong>HTTPError</strong> which are types we will declare next. </p>
<h2 id="routeprovider">RouteProvider</h2>
<p>This is what I would call the star of the show. <strong>RouteProvider</strong> defines a protocol for which we can build requests. By using a <em>protocol</em> we can give flexibility to how requests are formed. We can decide to implement the <strong>RouteProvider</strong> with a <em>class</em>, <em>struct</em>, or <em>enum</em>. I’ve decided to go with the <em>enum</em> approach. This provides users with a single source of truth. We know every time that a request is made to a specific endpoint it will be built using the same parameters. </p>
<pre><code>protocol RouteProvider {
    <span class="hljs-keyword">var</span> baseURL: URL { <span class="hljs-keyword">get</span> }
    <span class="hljs-keyword">var</span> path: <span class="hljs-built_in">String</span> { <span class="hljs-keyword">get</span> }
    <span class="hljs-keyword">var</span> method: HTTPMethod { <span class="hljs-keyword">get</span> }
    <span class="hljs-keyword">var</span> headers: [<span class="hljs-built_in">String</span>: <span class="hljs-built_in">String</span>] { <span class="hljs-keyword">get</span> }
}
</code></pre><h3 id="placeholderroute">PlaceHolderRoute</h3>
<p>Declare a Route which will implement the <strong>RouteProvider</strong> protocol. I’ve made use of the <em>JSONPlaceholder API</em> and added a single case to get users to demonstrate.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">PlaceHolderRoute</span> </span>{
    <span class="hljs-keyword">case</span> users
}

<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">PlaceHolderRoute</span>: <span class="hljs-title">RouteProvider</span> </span>{
    <span class="hljs-keyword">var</span> baseURL: <span class="hljs-type">URL</span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> url = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>) <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"Base URL could not be configured."</span>)
        }
        <span class="hljs-keyword">return</span> url
    }

    <span class="hljs-keyword">var</span> path: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">switch</span> <span class="hljs-keyword">self</span> {
        <span class="hljs-keyword">case</span> .users: <span class="hljs-keyword">return</span> <span class="hljs-string">"/users"</span>
        }
    }

    <span class="hljs-keyword">var</span> method: <span class="hljs-type">HTTPMethod</span> {
        <span class="hljs-keyword">switch</span> <span class="hljs-keyword">self</span> {
        <span class="hljs-keyword">case</span> .users: <span class="hljs-keyword">return</span> .<span class="hljs-keyword">get</span>(<span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-keyword">var</span> headers: [<span class="hljs-type">String</span> : <span class="hljs-type">String</span>] {
        <span class="hljs-keyword">return</span> [:]
    }
}
</code></pre><h2 id="httpmethod">HTTPMethod</h2>
<p>The <strong>HTTPMethod</strong> <em>enum</em> will be used to state which HTTP method to use for the request. We will only be supporting the most common HTTP method types in our framework. The HTTP spec does not limit the number of HTTP method types, in fact, there are other spec implementations that use methods like <em>“COPY”</em> and <em>“LOCK”</em> but you don’t come across such often.  </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">HTTPMethod</span> </span>{
    <span class="hljs-keyword">case</span> <span class="hljs-keyword">get</span>([<span class="hljs-type">String</span>: <span class="hljs-type">String</span>]? = <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">case</span> put(<span class="hljs-type">HTTPContentType</span>)
    <span class="hljs-keyword">case</span> post(<span class="hljs-type">HTTPContentType</span>)
    <span class="hljs-keyword">case</span> patch(<span class="hljs-type">HTTPContentType</span>)
    <span class="hljs-keyword">case</span> delete

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">var</span> rawValue: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">switch</span> <span class="hljs-keyword">self</span> {
        <span class="hljs-keyword">case</span> .<span class="hljs-keyword">get</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"GET"</span>
        <span class="hljs-keyword">case</span> .put: <span class="hljs-keyword">return</span> <span class="hljs-string">"PUT"</span>
        <span class="hljs-keyword">case</span> .post: <span class="hljs-keyword">return</span> <span class="hljs-string">"POST"</span>
        <span class="hljs-keyword">case</span> .patch: <span class="hljs-keyword">return</span> <span class="hljs-string">"PATCH"</span>
        <span class="hljs-keyword">case</span> .delete: <span class="hljs-keyword">return</span> <span class="hljs-string">"DELETE"</span>
        }
    }
}
</code></pre><p>We once again make use of associated values in our enums to enable us to pass in values to the <strong>HTTPMethod</strong>. </p>
<p>The <strong>GET</strong> case will enable us to pass in URL query parameters with our request. We can construct use <code>.get(["page": 2])</code> to construct a URL like: <code>http://api.test.com/content?page=2</code></p>
<p>For <em>PUT</em>, <em>POST</em> and, <em>PATCH</em> we make use of <strong>HTTPContentType</strong>. This type will enable us to post encoded JSON or even an encoded dictionary in the body of the request.</p>
<h2 id="httpcontenttype">HTTPContentType</h2>
<pre><code><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">HTTPContentType</span> </span>{
    <span class="hljs-keyword">case</span> json(<span class="hljs-type">Encodable?</span>)
    <span class="hljs-keyword">case</span> urlEncoded(<span class="hljs-type">EncodableDictionary</span>)

    <span class="hljs-keyword">var</span> headerValue: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">switch</span> <span class="hljs-keyword">self</span> {
        <span class="hljs-keyword">case</span> .json: <span class="hljs-keyword">return</span> <span class="hljs-string">"application/json"</span>
        <span class="hljs-keyword">case</span> .urlEncoded: <span class="hljs-keyword">return</span> <span class="hljs-string">"application/x-www-form-urlencoded"</span>
        }
    }
}
</code></pre><p>By setting the <em>headerValue</em> here we can tightly couple the expected header to the type being sent. This will ensure that we always send the right headers. </p>
<h2 id="encodabledictionary">EncodableDictionary</h2>
<p>This protocol URL encodes <em>Dictionary</em> keys and values and returns them as <em>Data</em>.
<strong>Input</strong>: <code>[“Name”: “Malcolm K”, “Emoji”: “🍩”]</code><br /><strong>Output</strong>: <code>Name=Malcolm%20K&amp;Emoji=%F0%9F%8D%A9</code> <em>(string representation of data)</em></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">protocol</span> <span class="hljs-title">EncodableDictionary</span> </span>{
    <span class="hljs-keyword">var</span> asURLEncodedString: <span class="hljs-type">String?</span> { <span class="hljs-keyword">get</span> }
    <span class="hljs-keyword">var</span> asURLEncodedData: <span class="hljs-type">Data?</span> { <span class="hljs-keyword">get</span> }
}

<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">Dictionary</span>: <span class="hljs-title">EncodableDictionary</span> </span>{

    <span class="hljs-keyword">var</span> asURLEncodedString: <span class="hljs-type">String?</span> {
        <span class="hljs-keyword">var</span> pairs: [<span class="hljs-type">String</span>] = []
        <span class="hljs-keyword">for</span> (key, value) <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span> {
            pairs.append(<span class="hljs-string">"\(key)=\(value)"</span>)
        }
        <span class="hljs-keyword">return</span> pairs
            .joined(separator: <span class="hljs-string">"&amp;"</span>)
            .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    }

    <span class="hljs-keyword">var</span> asURLEncodedData: <span class="hljs-type">Data?</span> { asURLEncodedString?.data(using: .utf8) }
}
</code></pre><h2 id="httperror">HTTPError</h2>
<p>When communicating with a server via internet errors are expected.  Errors can happen due to poor internet connectivity or the server is down. We need a way to handle these errors gracefully. Create and <strong>HTTPError</strong> struct with a nested Code <em>enum</em> with all the errors you wish to handle. </p>
<p><em>HTTPURLResponse</em> provides us with an error message given a status code. We will leverage this functionality to display an appropriate message. </p>
<pre><code><span class="hljs-built_in">print</span>(HTTPURLResponse.localizedString(forStatusCode: <span class="hljs-number">400</span>)) <span class="hljs-comment">// prints “bad request”</span>
</code></pre><p>We can decide to either make use of the system provided message or use the <strong>Code</strong> <em>enum</em> to provide a custom error message as seen below. </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">HTTPError</span>: <span class="hljs-title">Error</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Code</span>: <span class="hljs-title">Int</span> </span>{
        <span class="hljs-keyword">case</span> unknown                        = -<span class="hljs-number">1</span>
        <span class="hljs-keyword">case</span> networkUnreachable             = <span class="hljs-number">0</span>
        <span class="hljs-keyword">case</span> unableToParseResponse          = <span class="hljs-number">1</span>
        <span class="hljs-keyword">case</span> badRequest                     = <span class="hljs-number">400</span>
        <span class="hljs-keyword">case</span> internalServerError            = <span class="hljs-number">500</span>
    }

    <span class="hljs-keyword">let</span> route: <span class="hljs-type">RouteProvider?</span>
    <span class="hljs-keyword">let</span> response: <span class="hljs-type">HTTPURLResponse?</span>
    <span class="hljs-keyword">let</span> error: <span class="hljs-type">Error?</span>

    <span class="hljs-keyword">var</span> message: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">switch</span> <span class="hljs-type">Code</span>(rawValue: response?.statusCode ?? -<span class="hljs-number">1</span>) {
        <span class="hljs-keyword">case</span> .unknown:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Something went wrong"</span>
        <span class="hljs-keyword">case</span> .networkUnreachable:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Please check your internet connectivity"</span>
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> systemMessage
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> systemMessage: <span class="hljs-type">String</span> {
        <span class="hljs-type">HTTPURLResponse</span>.localizedString(forStatusCode: response?.statusCode ?? <span class="hljs-number">0</span>)
    }

}
</code></pre><p>Here we store a few properties: <em>code</em>, <em>route</em>, <em>response</em> and, <em>error</em>. This gives us flexibility as to how to handle the error. We can decide to show a <em>toast</em> with a message in the response. If needed we can retry the request as we have the <em>route</em>. We can also log an error to a logger or analytics service. </p>
<h2 id="httpresponse">HTTPResponse</h2>
<p>Finally, we have <strong>HTTPResponse</strong> which is a generic type constrained to <em>Decodable</em>. We constrain to <em>Decodable</em> as we expect JSON back from the server which we will decode to a model object. </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">HTTPResponse</span>&lt;<span class="hljs-title">T</span>: <span class="hljs-title">Decodable</span>&gt; </span>{
    <span class="hljs-keyword">let</span> route: <span class="hljs-type">RouteProvider</span>
    <span class="hljs-keyword">let</span> response: <span class="hljs-type">HTTPURLResponse?</span>
    <span class="hljs-keyword">let</span> data: <span class="hljs-type">Data?</span>

    <span class="hljs-keyword">var</span> decoded: <span class="hljs-type">T?</span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> data = data <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">T</span>.<span class="hljs-keyword">self</span>, from: data)
    }
}
</code></pre><h1 id="conclusion">Conclusion</h1>
<p>That brings us to the end of part one! Our goal was to design a <em>generic</em>, <em>typesafe</em> and, <em>declarative</em> API for our networking library. We started with this line of code giving us some errors. </p>
<pre><code><span class="hljs-keyword">let</span> publisher = client.request([<span class="hljs-type">User</span>].<span class="hljs-keyword">self</span>, from: .users)
</code></pre><p>No more errors. 👍
Well done on getting this far! 🥳
But, wait when we build and run nothing is happening yet? 🤔   </p>
<p>See you in part two where we will start building our <strong>URLRequests</strong> using <strong>Combine</strong> and handle server <em>responses</em>! </p>
<p><em>Thanks to  <a target="_blank" href="https://twitter.com/mpexgem">Mpendulo Ndlovu</a>  for his editorial work on this post.</em></p>
<h3 id="resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html#ID148">Swift Enum</a>  Documentation </li>
<li><a target="_blank" href="https://davedelong.com/blog/2020/06/27/http-in-swift-part-1/">HTTP in Swift</a>  by Dave DeLong </li>
<li><a target="_blank" href="https://www.avanderlee.com/swift/url-components/">URLs in Swift</a>  by Antoine van der Lee </li>
<li><a target="_blank" href="https://medium.com/@PhiJay/why-swift-enums-with-associated-values-cannot-have-a-raw-value-21e41d5ec11#:~:text=We%20had%20to%20do%20this,raw%20values%20or%20associated%20values.&amp;text=It's%20because%20of%20the%20definition,value%20of%20a%20particular%20type.">Why Swift enums with associated values can’t have a rawValue</a>  by Mischa Hildebrand</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Swift Network Layer Series]]></title><description><![CDATA[Welcome to the Swift Network Layer Series! 👋🏾
In this series, we will be covering how we can code our own declarative protocol-orientated networking layer using our beloved Swift.
Knowing how to communicate with a server and present the response da...]]></description><link>https://blog.malcolmk.com/swift-network-layer-series</link><guid isPermaLink="true">https://blog.malcolmk.com/swift-network-layer-series</guid><category><![CDATA[Swift]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Malcolm]]></dc:creator><pubDate>Thu, 27 Aug 2020 07:05:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1598448020911/8S3a8v_0I.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="welcome-to-the-swift-network-layer-series">Welcome to the Swift Network Layer Series! 👋🏾</h1>
<p>In this series, we will be covering how we can code our own declarative protocol-orientated networking layer using our beloved Swift.</p>
<p>Knowing how to communicate with a server and present the response data to a user is a vital skill every iOS developer should have. Over the years Apple has made enhancements to <code>URLSession</code> that make our lives as developers easier which have eradicated the need for third-party dependencies for trivial tasks. </p>
<h2 id="why">Why? 🤷🏼‍♀️</h2>
<p>So why would one write their own network layer when there are already so many good networking libraries out there? </p>
<p>Because it is time to break up with that networking library in favor of your own custom-built network layer 😎. It's time to understand what <em>"magic"</em> that library does,  <a target="_blank" href="https://twitter.com/samjarman/status/967548424542285824?s=20">remove unnecessary dependencies from your project</a>, gain full control, and level up your skills. </p>
<p>In 2018 I wrote my first Network Layer blog post -  <a target="_blank" href="https://medium.com/flawless-app-stories/writing-network-layer-in-swift-protocol-oriented-approach-4fa40ef1f908">Writing a Network Layer in Swift: Protocol-Oriented Approach</a>.
The post garnered a lot of engagement from the community so I feel like it's time for an update. While my previous post covers some key concepts that are still relevant today, a lot has changed in Swift since 2018.  <code>Result</code> has been added to the standard library, <code>Enums</code> can now have default associated values 😁, and with iOS 13 Apple gave us <code>Combine</code> which enables us to use functional reactive programming.  </p>
<h2 id="topics">Topics 📝</h2>
<p>The series will be covering some key concepts of networking in Swift. Some of the topics we will be covering are listed below: </p>
<ol>
<li>Designing the API 🤓</li>
<li>Building requests with Combine 🧬</li>
<li>Authentication 👮🏽‍♀️</li>
<li>Download Tasks 👇</li>
<li>Upload Tasks ☝️</li>
<li>Chaining Requests ⛓</li>
<li>Working with Protobufs 🤝</li>
</ol>
<h2 id="what-to-expect">What to expect 🕶</h2>
<p>At the end of the series, you should feel comfortable working with <code>URLSession</code> and be able to code your network layer.</p>
<p>During the series, I will implement things in my style and I encourage you to use your style wherever you see fit. The beauty of programming is that there are many ways to achieve the same task and we all have our own approaches. </p>
<p><em>I will share a link to the Github repo at the end of the series.</em> </p>
<h3 id="code-snippet">Code snippet 💻</h3>
<p>Let's take a quick look at what we will attempt to achieve. Below you will see an example of how the what we will be building can be used. This example demonstrates a call to the <em>JSON Placeholder API</em> to fetch a list of users. The request is type-safe and the response is decoded to a <code>User</code> model. <code>Client</code> defines the API we will be using make requests and <code>UserEndPoint</code> is an <code>Enum</code> conforming to a protocol that defines requests. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1598513873066/8kVP01zev.png" alt="carbon (1).png" /></p>
<h1 id="see-you-soon">See you soon 🚀</h1>
<p>If I have piqued your interest make sure to subscribe to my blog, follow me on Twitter, and let me know! </p>
<p><strong><em>See you in the first post of the series where we cover how we can define our API.</em></strong> 👋🏾</p>
]]></content:encoded></item></channel></rss>