<?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[Fabian Gröger]]></title><description><![CDATA[Fabian Gröger]]></description><link>https://fgroeger.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 31 Aug 2026 11:07:01 GMT</lastBuildDate><atom:link href="https://fgroeger.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Leveraging the MV Pattern in Swift: A FoodStore Example]]></title><description><![CDATA[Swift's powerful UI framework, SwiftUI, makes it incredibly easy to build dynamic and responsive user interfaces. One of the design patterns that aligns well with SwiftUI is the Model-View (MV) pattern. In this blog post, we'll explore how to impleme...]]></description><link>https://fgroeger.hashnode.dev/leveraging-the-mv-pattern-in-swift-a-foodstore-example</link><guid isPermaLink="true">https://fgroeger.hashnode.dev/leveraging-the-mv-pattern-in-swift-a-foodstore-example</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[architecture]]></category><category><![CDATA[iOS]]></category><dc:creator><![CDATA[Fabian Gröger]]></dc:creator><pubDate>Tue, 21 May 2024 20:24:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716322829940/4d68261c-7701-49d8-9c90-8c17225479b9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Swift's powerful UI framework, SwiftUI, makes it incredibly easy to build dynamic and responsive user interfaces. One of the design patterns that aligns well with SwiftUI is the Model-View (MV) pattern. In this blog post, we'll explore how to implement the MV pattern in Swift using a <code>FoodStore</code> example, showcasing how different views can share the same store via the environment, making view composition straightforward and efficient.</p>
<h2 id="heading-what-is-the-model-view-mv-pattern">What is the Model-View (MV) Pattern?</h2>
<p>The MV pattern separates the data (model) from the user interface (view). This separation promotes a clean architecture and enhances code maintainability and scalability. In SwiftUI, the environment acts as a conduit, allowing different views to access shared data easily.</p>
<h2 id="heading-setting-up-the-foodstore-model">Setting Up the FoodStore Model</h2>
<p>Let's start by defining our <code>FoodStore</code> model. This model will manage a list of food items, including functionalities to add and remove items.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> Combine

@<span class="hljs-type">Observable</span>
<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FoodStore</span> </span>{
    <span class="hljs-keyword">var</span> foods: [<span class="hljs-type">Food</span>] = []

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addFood</span><span class="hljs-params">(name: String, quantity: Int)</span></span> {
        <span class="hljs-keyword">let</span> newFood = <span class="hljs-type">Food</span>(name: name, quantity: quantity)
        foods.append(newFood)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">removeFood</span><span class="hljs-params">(at index: Int)</span></span> {
        foods.remove(at: index)
    }
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Food</span>: <span class="hljs-title">Identifiable</span> </span>{
    <span class="hljs-keyword">let</span> id = <span class="hljs-type">UUID</span>()
    <span class="hljs-keyword">let</span> name: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> quantity: <span class="hljs-type">Int</span>
}
</code></pre>
<p>Here, <code>FoodStore</code> uses the <code>@Observable</code> macro, which allows SwiftUI views to automatically update when the data changes. The <code>Food</code> struct represents a food item with a unique identifier, name, and quantity.</p>
<h2 id="heading-creating-views-that-use-foodstore">Creating Views that Use FoodStore</h2>
<p>Next, we'll create different views that utilize the <code>FoodStore</code> model. By using the <code>@Environment</code> property wrapper, we can easily share the <code>FoodStore</code> instance across multiple views.</p>
<h3 id="heading-foodlistview">FoodListView</h3>
<p>The <code>FoodListView</code> displays the list of food items and provides a button to add new items.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">FoodListView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">Environment</span>(<span class="hljs-type">FoodStore</span>.<span class="hljs-keyword">self</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> foodStore

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">NavigationView</span> {
            <span class="hljs-type">List</span> {
                <span class="hljs-type">ForEach</span>(foodStore.foods) { food <span class="hljs-keyword">in</span>
                    <span class="hljs-type">HStack</span> {
                        <span class="hljs-type">Text</span>(food.name)
                        <span class="hljs-type">Spacer</span>()
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"\(food.quantity)"</span>)
                    }
                }
                .onDelete(perform: deleteFood)
            }
            .navigationTitle(<span class="hljs-string">"Food List"</span>)
            .navigationBarItems(trailing:
                <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">AddFoodView</span>()) {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"Add Food"</span>)
                }
            )
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">deleteFood</span><span class="hljs-params">(at offsets: IndexSet)</span></span> {
        <span class="hljs-keyword">for</span> index <span class="hljs-keyword">in</span> offsets {
            foodStore.removeFood(at: index)
        }
    }
}
</code></pre>
<h3 id="heading-addfoodview">AddFoodView</h3>
<p>The <code>AddFoodView</code> allows users to add new food items to the store.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AddFoodView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">Environment</span>(<span class="hljs-type">FoodStore</span>.<span class="hljs-keyword">self</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> foodStore

    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> foodName: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> foodQuantity: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">Form</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Food Name"</span>, text: $foodName)
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Quantity"</span>, text: $foodQuantity)
                .keyboardType(.numberPad)

            <span class="hljs-type">Button</span>(action: addFood) {
                <span class="hljs-type">Text</span>(<span class="hljs-string">"Add Food"</span>)
            }
        }
        .navigationTitle(<span class="hljs-string">"Add New Food"</span>)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addFood</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> quantity = <span class="hljs-type">Int</span>(foodQuantity), !foodName.isEmpty {
            foodStore.addFood(name: foodName, quantity: quantity)
        }
    }
}
</code></pre>
<h2 id="heading-composing-views-with-environment">Composing Views with Environment</h2>
<p>Now, we'll compose our main view and inject the <code>FoodStore</code> instance into the environment, making it accessible to all child views.</p>
<pre><code class="lang-swift">@main
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">FoodStoreApp</span>: <span class="hljs-title">App</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> foodStore = <span class="hljs-type">FoodStore</span>()

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">Scene</span> {
        <span class="hljs-type">WindowGroup</span> {
            <span class="hljs-type">FoodListView</span>()
                .environment(foodStore)
        }
    }
}
</code></pre>
<p>By using the <code>@State</code> property wrapper, we ensure that <code>foodStore</code> is created once and managed by SwiftUI. The <code>environment</code> modifier then shares this instance with all views in the view hierarchy.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Implementing the MV pattern in Swift using SwiftUI and the <code>@Environment</code> property wrapper allows for clean and efficient view composition. In our <code>FoodStore</code> example, we've demonstrated how easy it is to create and manage shared data across multiple views. This pattern not only simplifies state management but also enhances the scalability and maintainability of your codebase.</p>
<p>The MV pattern in Swift, especially with SwiftUI, is a powerful approach that leverages the best of Swift's declarative nature. By separating the model from the view and utilizing the environment for shared data, you can build dynamic and responsive interfaces with ease.</p>
]]></content:encoded></item><item><title><![CDATA[Why Completion Handlers Are Ruining Your Swift Code - Time for a Change!]]></title><description><![CDATA[Swift is a powerful and versatile programming language known for its strong safety features. However, when it comes to asynchronous programming, there have been several approaches to handle completion handlers that can be error-prone. In this blog po...]]></description><link>https://fgroeger.hashnode.dev/why-completion-handlers-are-ruining-your-swift-code-time-for-a-change</link><guid isPermaLink="true">https://fgroeger.hashnode.dev/why-completion-handlers-are-ruining-your-swift-code-time-for-a-change</guid><category><![CDATA[Swift]]></category><category><![CDATA[async/await]]></category><dc:creator><![CDATA[Fabian Gröger]]></dc:creator><pubDate>Wed, 17 Apr 2024 20:21:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713386279908/c8c91448-0434-4248-a975-b9954cb925d2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<p>Swift is a powerful and versatile programming language known for its strong safety features. However, when it comes to asynchronous programming, there have been several approaches to handle completion handlers that can be error-prone. In this blog post, we will explore why completion handlers can be problematic and how modern Swift technologies like async/await offer a superior alternative. We'll use an example to demonstrate the pitfalls of completion handlers and showcase the advantages of the more modern approach.</p>
<h2 id="heading-the-problem-with-completion-handlers">The Problem with Completion Handlers</h2>
<p>Completion handlers are often used in Swift to manage asynchronous operations, like network requests or file I/O. They require a callback function to be executed once the asynchronous task is completed. While they work, they can lead to some common issues:</p>
<ul>
<li><p><strong>1. Callback Hell:</strong> Asynchronous code written using completion handlers can quickly become nested and difficult to read, leading to a structure commonly referred to as "Callback Hell." This makes code maintenance and debugging a challenging task.</p>
</li>
<li><p><strong>2. Error Handling:</strong> Error handling is often inconsistent and can be prone to error when using completion handlers. Developers must remember to call the completion handler in both success and failure cases.</p>
</li>
<li><p><strong>3. Leaked Resources:</strong> If the completion handler is not executed properly, it may lead to resource leaks, as the developer might forget to release resources or close connections.</p>
</li>
</ul>
<p>A Common Pitfall: Forgetting to Call the Completion Handler</p>
<p>To illustrate the problem, let's consider an example of downloading data from a web API using a completion handler. We'll create a function that downloads a JSON response and passes the result back using a completion handler:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">downloadData</span><span class="hljs-params">(completion: @escaping <span class="hljs-params">(Result&lt;Data, Error&gt;)</span></span></span> -&gt; <span class="hljs-type">Void</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://example.com/data.json"</span>) <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-type">URLSession</span>.shared.dataTask(with: url) { data, response, error <span class="hljs-keyword">in</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> error = error {
            completion(.failure(error))
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> data = data <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Oops! We forgot to call the completion handler here.</span>
            <span class="hljs-keyword">return</span>
        }

        completion(.success(data))
    }.resume()
}
</code></pre>
<p>In this example, there is a critical mistake - we forgot to call the completion handler if the data is nil. This can lead to unexpected behavior and resource leaks in a real-world scenario.</p>
<h2 id="heading-a-better-approach-using-asyncawait">A Better Approach: Using async/await</h2>
<p>Swift introduced native support for asynchronous programming using async/await. With this approach, the code becomes more readable, less error-prone, and easier to maintain. Let's rewrite the example using async/await:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">downloadData</span><span class="hljs-params">()</span></span> async <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-type">Data</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://example.com/data.json"</span>) <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">throw</span> <span class="hljs-type">MyError</span>.invalidURL
    }

    <span class="hljs-keyword">let</span> (data, <span class="hljs-number">_</span>) = <span class="hljs-keyword">try</span> await <span class="hljs-type">URLSession</span>.shared.data(from: url)
    <span class="hljs-keyword">return</span> data
}
</code></pre>
<p>Using async/await, we can handle errors more gracefully by throwing exceptions. The code is linear, making it easier to follow.</p>
<h2 id="heading-an-alternative-approach-using-combine-publishers">An Alternative Approach: Using Combine Publishers</h2>
<p>Combine is a powerful framework for reactive and asynchronous programming in Swift. While it's a valuable tool, it's essential to consider your project's specific requirements and your team's familiarity with Combine. Here's how the same task can be accomplished using Combine publishers:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Combine

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">downloadData</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">AnyPublisher</span>&lt;<span class="hljs-type">Data</span>, <span class="hljs-type">Error</span>&gt; {
    <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://example.com/data.json"</span>) <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">Fail</span>(error: <span class="hljs-type">MyError</span>.invalidURL).eraseToAnyPublisher()
    }

    <span class="hljs-keyword">return</span> <span class="hljs-type">URLSession</span>.shared.dataTaskPublisher(<span class="hljs-keyword">for</span>: url)
        .<span class="hljs-built_in">map</span>(\.data)
        .eraseToAnyPublisher()
}
</code></pre>
<p>Combine publishers offer a clean and declarative way to handle asynchronous operations, with built-in error handling and composability.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>While completion handlers have been a traditional way to manage asynchronous code in Swift, they come with inherent pitfalls such as callback hell and error handling challenges. Modern Swift technologies like async/await provide a superior alternative, making your code more readable, maintainable, and less error-prone. As Swift evolves, it's essential for developers to embrace these new techniques to write more efficient and robust asynchronous code.</p>
]]></content:encoded></item></channel></rss>