<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>iOS Coffee Break</title>
        <link>https://www.ioscoffeebreak.com</link>
        <description>Welcome to iOS Coffee Break, a place for iOS devs to share their articles, tips and apps.</description>
        <lastBuildDate>Mon, 20 Apr 2026 07:25:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>iOS Coffee Break using Feed Generator</generator>
        <language>en</language>
        <copyright>© Copyright 2026. iOS Coffee Break. All rights reserved.</copyright>
        <item>
            <title><![CDATA[What One Week with GitHub Copilot Taught Me]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue71</link>
            <guid>71</guid>
            <pubDate>Mon, 20 Apr 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I finally went all in on agentic coding using GitHub Copilot at work. Here are my honest first impressions after one full week of experimenting with AI.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #71</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Until recently, I was still skeptical about using <strong>AI for coding</strong>!</p>
<p>I think part of that skepticism came from not fully trusting the quality of the output. Another part came from not wanting to become dependent on suggestions I did not fully understand. And, if I am being honest, I also felt these tools often looked much better in demos than they did in real project work.</p>
<p>That started to change this past week.</p>
<p>For a full week, I used <strong>GitHub Copilot</strong> much more intentionally in my day-to-day work. Not just for quick autocomplete suggestions, but as part of the actual development flow: asking it to help me reason about changes, break down tasks and move faster through implementation.</p>
<p>By the end of the week, my perspective was different.</p>
<p>This edition is a reflection on that experience: what worked, what did not, and what helped me move from resistance to a more practical mindset. I increasingly feel that this is something we should learn to work with instead of spending too much energy fighting against it.</p>
<blockquote>
<p>These thoughts come from my experience using the GitHub Copilot Business plan. Do not take them as granted, they are just honest notes from my own daily workflow.</p>
</blockquote>
<h2>My setup during this week</h2>
<p>At first, I wanted to use Copilot straight from Xcode through <a href="https://github.com/github/CopilotForXcode">CopilotForXcode</a>.</p>
<p>I gave it a fair try, but it still does not feel reliable enough for my day-to-day work. What ended up working better for me was this:</p>
<ul>
<li><strong>Xcode</strong> for my regular development work</li>
<li><strong>Visual Studio Code</strong> when I want to use the agent in a more intentional way</li>
</ul>
<p>It is not the ideal setup, but it has been much more dependable.</p>
<h2>What helped the most</h2>
<p>The one thing that improved the experience the most was this: <strong>start a new conversation for each new feature</strong>.</p>
<p>I noticed that when a conversation became too long, the agent gradually lost focus. In some cases, that also led to hallucinations.</p>
<p>Keeping each conversation tied to a specific goal gave me much better and more predictable results.</p>
<h2>Where I went wrong more than once</h2>
<p>A mistake I made several times was trying to get too much done in a single prompt.</p>
<p>When I asked for a large change all at once, the agent often struggled to stay focused. I would see it:</p>
<ul>
<li>touch files I did not mean to change</li>
<li>make edits unrelated to the original task</li>
<li>move away from the outcome I actually wanted</li>
</ul>
<p>Now, whenever I notice that happening, I pause and break the task into smaller parts.</p>
<p>What works better for me is:</p>
<ul>
<li>start by asking for a plan</li>
<li>move through the work step by step</li>
<li>review each step before going further</li>
</ul>
<p>This made the workflow much safer and a lot less noisy.</p>
<h2>MCP support ended up being really helpful</h2>
<p>One other thing I explored this week was <strong>MCP</strong> support.</p>
<p>I set up the <a href="https://github.com/mcp/com.atlassian/atlassian-mcp-server">Atlassian MCP Server</a>, and it worked surprisingly well for giving the agent richer context about my tasks.</p>
<p>Having Jira details available in the conversation made it easier for the agent to stay aligned with what I was actually trying to do.
That mattered more than I expected, especially when the work involved product requirements, task history, or details that were not obvious from the code alone.</p>
<p>In practice, this was one of the improvements I found most valuable!</p>
<h2>The biggest takeaway for me</h2>
<p>If there is one thing this week made clear to me, it is this:</p>
<p><strong>Make sure you understand the fix before accepting it.</strong></p>
<p>If I cannot explain why a solution works, then I am not in a good position to validate it. And if I cannot validate it, I should not be relying on it.</p>
<p>Copilot can speed up the process, but it does not remove our responsibility to make sure the code is correct.</p>
<h2>Final thoughts</h2>
<p>After spending a week with GitHub Copilot in my iOS workflow, my impression is positive, though definitely more realistic now.</p>
<p>It can be a very useful tool when the problem is clearly defined and the context is solid. But once the scope gets too wide and validation becomes weaker, things can go off track quite quickly.</p>
<p>The biggest change for me is not that I now trust the tool blindly. It is that I now understand better where it fits in my workflow, and where I need to slow down and think for myself.</p>
<p>I plan to keep using it, just much more intentionally than I did on day one.</p>
<p>Have a great week ahead 🤎</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Editorial</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/71.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Pixels & People]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue70</link>
            <guid>70</guid>
            <pubDate>Mon, 09 Mar 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[This week our app design team gathered at our Aveiro office for three days focused on refining the UI-tweaking details, polishing pixels, sharing meals and enjoying some great moments together.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #70</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Can you believe it's already March? February seemed to fly by.</p>
<p>This week our app design team gathered at our Aveiro office for three days focused on refining the UI-tweaking details, polishing pixels, sharing meals and enjoying some great moments together.</p>
<p>Even though I strongly support remote work, I truly value these in-person work meetups.
They help strengthen team connections and give us the chance to know the real people behind the avatars and Microsoft Teams windows.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://kylebrowning.com/posts/modularizing-swift-apps-with-spm/">Modularizing Swift Apps with SPM</a></h2>
<p>If you've ever worked on an app that grew beyond a small set of files, you probably know the pain: <strong>slower builds and small changes triggering recompilation across the entire target</strong>.</p>
<p><a href="https://www.linkedin.com/in/kyle-browning-eng-manager">Kyle</a> explains how to organize a Swift app using local Swift packages with well-defined layer boundaries.
By separating features, services, and shared components, large projects become easier to maintain and test.
This article is part of a series, and it's definitely worth reading the rest of the posts.</p>
<h2><a href="https://livsycode.com/best-practices/nscache-in-swift-a-practical-guide/">NSCache in Swift: A Practical Guide</a></h2>
<p>In <a href="https://x.com/livsycode">Artem's</a> latest article, he explores how <strong>NSCache</strong> actually works and where it fits within a real production iOS architecture.</p>
<p>When dealing with heavy feeds, rich text rendering pipelines or complex view hierarchies, this caching layer can help eliminate unnecessary recomputation while keeping data correctness intact.</p>
<h2><a href="https://mehmetbaykar.com/posts/essential-swift-package-manager-commands/">Essential Swift Package Manager Commands</a></h2>
<p><strong>Swift Package Manager</strong> includes many helpful commands beyond simply building packages, though many developers only use a small portion of them (myself included).</p>
<p><a href="https://mastodon.cloud/@mehmetbaykar">Mehmet</a> shares a practical list of commands that can simplify everyday workflows, covering everything from building and running packages to testing and preparing release builds.</p>
<h2><a href="https://ruiper.es/posts/agentic-coding/">Agentic Coding</a></h2>
<p>In this article, <a href="https://x.com/peres">Rui</a> writes about his experience using <strong>AI for coding along</strong>, sharing how adopting agent-driven workflows allowed AI to plan tasks, write code, run tests, and iterate with minimal manual input.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Community</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/70.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👋 What's New in the Community 🙆‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue69</link>
            <guid>69</guid>
            <pubDate>Mon, 23 Feb 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[It's been a busy week at work, but I still wanted to pass along a few articles and updates that stood out to me recently.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #69</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>It's been a busy week at work, but I still wanted to pass along a few articles and updates that stood out to me recently.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://blog.cocoapods.org/CocoaPods-Specs-Repo/">🪦 CocoaPods Trunk Read-only Plan</a></h2>
<p>After <strong>15</strong> years of dedicated service, <strong>CocoaPods</strong> is coming to an end!
Starting <strong>December 2, 2026</strong>, the CocoaPods trunk will switch to permanent read-only mode. No new libraries will be added, and no existing ones will receive updates.</p>
<p>If you're an iOS developer still relying on CocoaPods, it's time to begin gradually moving over to <strong>Swift Package Manager</strong>.</p>
<h2><a href="https://buczel.com/blog/fastlane-screenshots-ios/">📸 Automated App Store Screenshots with Fastlane: A Practical Guide</a></h2>
<p>I'm pretty sure most of us rely on <strong>Fastlane</strong> in our projects for some level of automation.
But are we really making the most of what it offers? I know I'm not! 😅</p>
<p>In his guide, <a href="https://x.com/kamil_buczel">Kamil</a> explains how to set up automated screenshots and highlights why building solid test infrastructure is a worthwhile investment for every release cycle.</p>
<h2><a href="https://artemnovichkov.com/blog/tracking-token-usage-in-foundation-models">💵 Tracking token usage in Foundation Models</a></h2>
<p>With <code>iOS 26.4</code>, Apple introduced <strong>token usage tracking</strong> in the <strong>Foundation Models</strong> framework, enabling developers to monitor computational costs and context limits for on-device AI models.</p>
<p><a href="https://x.com/iosartem">Artem</a> published a great piece this week diving into the topic, exploring APIs that let you measure token usage at different levels, from single instructions all the way to complete conversation transcripts.</p>
<h2><a href="https://livsycode.com/swift/how-to-measure-execution-speed-in-swift/">⏰ How to measure execution speed in Swift</a></h2>
<p>There are many scenarios where it's useful to measure how quickly your code runs, whether you're verifying the performance of network requests or developing an analytics provider.</p>
<p>Although <a href="https://x.com/livsycode">Artem's</a> article on this subject is nearly two years old, the techniques he describes are still relevant and can help determine when performance optimization is important.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Community</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/69.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Part 4 of Start building with Rive for iOS]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue68</link>
            <guid>68</guid>
            <pubDate>Mon, 02 Feb 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, we're moving on to part 4 of the series, where we'll explore topics like creating workflows with Rive Scripting and improving the animation logic using the AI agent.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #68</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Last week, we carried on with our <strong>&quot;Start building with Rive for iOS&quot;</strong> series and wrapped up <strong>part 3</strong>.</p>
<blockquote>
<p>If you haven't had a chance to read it yet, I recommend <a href="/issue/issue67">checking it out</a> first to get the most value from the series.</p>
</blockquote>
<p>Now, we're moving on to <strong>part 4</strong> and <strong>last edition of the series</strong>, where we'll explore topics like <strong>creating advanced workflows with Rive Scripting and improving the animation logic using the AI coding agent.</strong></p>
<h2>The Plan</h2>
<p>In this edition, we'll put together a <strong>particle system using the new Scripting feature</strong> and produce a <strong>fully dynamic falling-particle effect</strong>.
To wrap things up, we'll export the Rive animation and run it with the Rive runtime on iOS.</p>
<blockquote>
<p>If you haven't worked with Scripting before, I recommend checking out <a href="https://www.youtube.com/watch?v=Zh76EkkkjI8">Rive's official Scripting videos</a> before continuing.</p>
</blockquote>
<h3>Creating Artboards</h3>
<p>To start, we'll create an artboard for a single particle in the <a href="https://rive.app/editor">Rive editor</a>.
I'll set its dimensions to <code>200×200</code> pixels and name it <code>Particle</code>.
Then, I'll upload an image of my newsletter sticker and place it onto the artboard.
After that, I'll align it to the center, scale it so it fills the artboard, and turn the artboard into a component so it can be reused later.</p>
<p>At this point, we have a reusable particle component.
Here's what it looks like:</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/particle-artboard.webp&quot;
alt=&quot;Turning the Particle artboard into a component.&quot;
link=&quot;/issues/issue68/particle-artboard.webp&quot;
caption=&quot;Turning the Particle artboard into a component.&quot;
/&gt;</p>
<p>Next, we'll add the main artboard, which will be used to build the actual particle effect.</p>
<p>Let's create a new artboard sized at <code>850×1650</code> pixels and name it <code>CoffeeParticles</code>.
We'll also turn this artboard into a component.
Here's the result:</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/coffee-particles-artboard.webp&quot;
alt=&quot;Turning the CoffeeParticles artboard into a component.&quot;
link=&quot;/issues/issue68/coffee-particles-artboard.webp&quot;
caption=&quot;Turning the CoffeeParticles artboard into a component.&quot;
/&gt;</p>
<p>Finally, we'll create a script capable of generating these particles dynamically.</p>
<h3>Creating Scripts</h3>
<p>To add a script, open the toolbox and select a type of script.
I'll choose a <code>Node Script</code> for this setup.
<code>Node scripts</code> allow you to draw shapes, images, text, artboards, and more.
Rive automatically provides some starter code, which we'll modify and reuse to build our particle system.</p>
<pre><code class="language-swift">-- Define the script's data and inputs.
type MyNode = {}

-- Called once when the script initializes.
function init(self: MyNode): boolean
  return true
end

-- Called every frame to advance the simulation.
-- 'seconds' is the elapsed time since the previous frame.
function advance(self: MyNode, seconds: number): boolean
  return false
end

-- Called when any input value changes.
function update(self: MyNode) end

-- Called every frame (after advance) to render the content.
function draw(self: MyNode, renderer: Renderer) end


-- Return a factory function that Rive uses to build the Node instance.
return function(): Node&lt;MyNode&gt;
  return {
    init = init,
    advance = advance,
    update = update,
    draw = draw,
  }
end
</code></pre>
<p>Perfect! Next, let's hook up the particle artboard to the script.</p>
<h3>Connecting the Artboard to the Script</h3>
<p>Right now, the script doesn't have access to any artboards, so we'll need to set that up.
To do this, we'll add an artboard input to the script and connect it directly to the particle artboard.</p>
<p>In the inputs section of the script, add a new artboard input.
Set its property to <code>Input</code> and specify the type as <code>Artboard</code>.</p>
<pre><code class="language-swift">-- Define the script's data and inputs.
type MyNode = {
  particle: Input&lt;Artboard&gt;,
}

[...]
</code></pre>
<blockquote>
<p>If the syntax looks unfamiliar, Rive's official scripting tutorials cover this in detail.</p>
</blockquote>
<p>Every input we declare must also be initialized.
Scroll down to the code section where all variables are initialized and add this new input there as well.
Here, we'll reference the particle input and set its value to <code>late</code>, which tells <strong>Rive</strong> that the value will be supplied from outside the script rather than defined internally.</p>
<pre><code class="language-swift">[...]

-- Return a factory function that Rive uses to build the Node instance.
return function(): Node&lt;MyNode&gt;
  return {
    init = init,
    advance = advance,
    update = update,
    draw = draw,
    particle = late(),
  }
end
</code></pre>
<p>After saving the script, a new artboard input will appear in the script's properties panel, ready to be assigned.
When you open it, you'll be able to select the <code>Particle</code> component.</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/assigning-artboard-script.webp&quot;
alt=&quot;Assigning the Particle artboard to the script.&quot;
link=&quot;/issues/issue68/assigning-artboard-script.webp&quot;
caption=&quot;Assigning the Particle artboard to the script.&quot;
/&gt;</p>
<p>The next step is to use the <strong>draw</strong> and <strong>advance</strong> functions to render the script on screen.
The <strong>advance</strong> function runs every frame and updates the animation logic while <strong>draw</strong> runs after that and renders the element to the screen.</p>
<p>So, let's use <code>self</code> to access the particle input we created and then call the draw function on it.</p>
<pre><code class="language-swift">[...]

-- Called every frame (after advance) to render the content.
function draw(self: MyNode, renderer: Renderer) 
  self.particle:draw(renderer)
end

[...]
</code></pre>
<p>After this, we'll use the <strong>AI</strong> agent to handle the code and the more complex logic.</p>
<p>Next, let's update the <strong>advance</strong> function. We'll use self again to access the particle input, call its advance function and pass in the seconds value.</p>
<pre><code class="language-swift">[...]

-- Called every frame to advance the simulation.
-- 'seconds' is the elapsed time since the previous frame.
function advance(self: MyNode, seconds: number): boolean
  self.particle:advance(seconds)
  return false
end

[...]
</code></pre>
<p>Once saved, we should now see the particle on screen.</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/draw.webp&quot;
alt=&quot;Selecting the Particle artboard.&quot;
link=&quot;/issues/issue68/draw.webp&quot;
caption=&quot;Selecting the Particle artboard.&quot;
/&gt;</p>
<h3>Setting the Artboard's width and height</h3>
<p>Next, we want the particle to travel from the top of the artboard all the way to the bottom.
To make this happen, the script needs to be aware of the artboard's dimensions.</p>
<p>So, we'll add two numeric inputs to represent the artboard's width and height.</p>
<pre><code class="language-swift">-- Define the script's data and inputs.
type MyNode = {
  particle: Input&lt;Artboard&gt;,
  screenWidth: Input&lt;number&gt;,
  screenHeight: Input&lt;number&gt;,
}

[...]
</code></pre>
<p>After that, we'll initialize these values.</p>
<pre><code class="language-swift">[...]

-- Return a factory function that Rive uses to build the Node instance.
return function(): Node&lt;MyNode&gt;
  return {
    init = init,
    advance = advance,
    update = update,
    draw = draw,
    particle = late(),
    screenWidth = 850,
    screenHeight = 1650,
  }
end
</code></pre>
<p>Once the script is saved, we'll see two new input fields appear.
Now we can move on to the fun part, <strong>working with the AI Agent</strong>!</p>
<p>We'll use the agent to animate the particle, create duplicates, and trigger various actions, allowing us to build a fully dynamic particle system using nothing but scripting.</p>
<h3>Building the Falling Animation with the AI Agent</h3>
<p>To begin, we'll use a simple prompt just to confirm everything is set up correctly.
In this case, we'll tell the script to position the particles at the exact center of the screen.</p>
<p>To interact with the agent, open the agent tab and enter a prompt. Here's the one I used:</p>
<pre><code class="language-swift">Modify the existing 'CoffeeParticlesFactory' script.

Center the Particle artboard in the middle of the screen.

Use the existing variables:
- screenWidth
- screenHeight

Set the Particle position so it is centered on both X and Y based on these values.
</code></pre>
<p>With that, we've created our first bit of logic using the AI agent.</p>
<p>Below is the script generated by the AI agent:</p>
<pre><code class="language-swift">[...]

-- Called every frame (after advance) to render the content.
function draw(self: MyNode, renderer: Renderer)
  -- Center the particle artboard on the screen
  renderer:save()
  renderer:transform(
    Mat2D.withTranslation(self.screenWidth / 2, self.screenHeight / 2)
  )
  self.particle:draw(renderer)
  renderer:restore()
end

[...]
</code></pre>
<p>Now, let's build a single animation for the particle.
We'll tell the agent to generate a looping animation where the particle begins just above the top edge of the screen.</p>
<p>From there, it will fall all the way to the bottom over a duration of <code>3 seconds</code>.
Once it reaches the bottom, the animation finishes and instantly starts over, looping endlessly.</p>
<p>Here is the second prompt:</p>
<pre><code class="language-swift">Add a looping falling animation to the Particle artboard.

Requirements:
- The animation should loop continuously.
- Duration: 3 seconds.
- Start the particle above the top edge of the screen (outside bounds).
- End the particle below the bottom edge of the screen (outside bounds).
- Use ease in for the motion.
- When the animation loops, the particle should jump back to the starting position above the screen, without visible popping.
</code></pre>
<p>Here is the animation when played:</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/particle-loop.gif&quot;
alt=&quot;Playing the particle looping animation.&quot;
link=&quot;/issues/issue68/particle-loop.gif&quot;
caption=&quot;Playing the particle looping animation.&quot;
/&gt;</p>
<p>Now that we have a single animation in place, let's duplicate it and transform it into a full particle effect.</p>
<h3>Building a Particle Effect</h3>
<p>To make this more dynamic, we'll introduce inputs that let us control the number of particles displayed on the screen and randomize their initial positions so they're evenly distributed rather than clustered together.
We'll also stagger the animation so the particles begin falling at different moments.</p>
<p>First, create a new input named <code>particlesCount</code> and set its initial value to <strong>10</strong>.</p>
<pre><code class="language-swift">-- Define the script's data and inputs.
type MyNode = {
  particle: Input&lt;Artboard&gt;,
  screenWidth: Input&lt;number&gt;,
  screenHeight: Input&lt;number&gt;,
  [...]
  particlesCount: Input&lt;number&gt;,
}

[...]

-- Return a factory function that Rive uses to build the Node instance.
return function(): Node&lt;MyNode&gt;
  return {
    init = init,
    advance = advance,
    update = update,
    draw = draw,
    particle = late(),
    screenWidth = 500,
    screenHeight = 500,
    [...]
    particlesCount = 10,
  }
end
</code></pre>
<p>Next, we'll move to the agent and tell it to duplicate the particle artboard according to the <code>particlesCount</code> input we just added.
We'll also have it assign a random <strong>X</strong> and <strong>Y</strong> position to each particle, ensuring they're scattered across the screen instead of dropping along a single path.</p>
<p>Here is the prompt I used:</p>
<pre><code class="language-swift">Modify the existing 'CoffeeParticlesFactory' script to spawn multiple particles based on 'particlesCount'.

Requirements:
- Create 'particlesCount' particles (instances) of the Particle artboard.
- Each particle should use the existing falling animation with a loop duration of 3 seconds.
- For each particle, randomize a different X position across the screen width.
- Randomize a different Y offset so particles start at different times (staggered, not synchronized).

Loop behavior:
- When a particle exits the bottom of the screen (end of the 3s loop), reset it to the top (outside bounds) and re-randomize its X position so the falling pattern keeps changing over time.

Keep everything else unchanged.
</code></pre>
<p>At this point, the single particle we designed is replicated into multiple particles.
The end result is a simple falling animation made up of <strong>10</strong> individual particles.</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/falling-particles-animation.gif&quot;
alt=&quot;Playing the falling particles animation.&quot;
link=&quot;/issues/issue68/falling-particles-animation.gif&quot;
caption=&quot;Playing the falling particles animation.&quot;
/&gt;</p>
<blockquote>
<p>If you're curious, I've made this animation available on the Rive Marketplace, where you can check it out <a href="https://rive.app/community/files/26074-48716-falling-coffee-particles">here</a>.</p>
</blockquote>
<h3>Adding the Animation to the App</h3>
<p>Before the app can use the animation, it needs to be exported.
To do this, select <code>Export</code> &gt; <code>For runtime</code>.
This generates a <code>.riv</code> file, which I'll name <code>particles.riv</code>.</p>
<p>Next, I created a view and initialize a <strong>RiveViewModel</strong> using the exported Rive file.</p>
<p>This is what the view implementation looks like:</p>
<pre><code class="language-swift">import RiveRuntime
import SwiftUI

struct ScriptingView: View {
    @State private var vm: RiveViewModel?

    var body: some View {
        ZStack {
            Group {
                if let vm = vm {
                    vm.view()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .ignoresSafeArea()
                } else {
                    VStack {
                        Text(&quot;Missing .riv file&quot;)
                            .font(.headline)
                        Text(&quot;Add `particles.riv` to the app target (Copy Bundle Resources), then rebuild.&quot;)
                            .font(.subheadline)
                            .foregroundStyle(.secondary)
                            .multilineTextAlignment(.center)
                    }
                    .padding()
                }
            }
        }
        .navigationTitle(&quot;Scripting&quot;)
        .onAppear {
            // avoid RiveRuntime fatalError in SwiftUI previews when the resource isn't bundled yet.
            if Bundle.main.url(forResource: &quot;particles&quot;, withExtension: &quot;riv&quot;) != nil {
                vm = RiveViewModel(fileName: &quot;particles&quot;)
            }
        }
    }
}
</code></pre>
<blockquote>
<p>Rive Scripting is supported in the Rive iOS runtime starting from version 6.13.0, so be sure you're on that version or newer. Anything older won't work. Speaking from experience ... I learned that the hard way 🙂</p>
</blockquote>
<p>And here's the final outcome:</p>
<p>&lt;StaticHalfWidthRemoteImage
src=&quot;/issues/issue68/app-with-scripting.gif&quot;
alt=&quot;Playing the particle looping animation in the app.&quot;
link=&quot;/issues/issue68/app-with-scripting.gif&quot;
caption=&quot;Playing the particle looping animation in the app.&quot;
/&gt;</p>
<blockquote>
<p>In case you are interested in the source code, feel free to check out the <a href="https://github.com/henriquestiagoo/animated-tree/tree/rive-scripting">repository</a>.</p>
</blockquote>
<h2>🤝 Wrapping Up</h2>
<p><strong>Rive Scripting</strong> was recently made available to everyone, and I wanted to dive into it and share a beginner-friendly overview with you.
It's definitely a powerful on-ramp for designers and a speed boost for developers!</p>
<p>You can build fully interactive animations without needing any programming background.
That brings the <strong>&quot;Start building with Rive for iOS&quot;</strong> series to a close!</p>
<p>I hope you enjoyed it as much as I did 😃</p>
<h2>References</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=Zh76EkkkjI8">Scripting: Getting started</a></li>
<li><a href="https://rive.app/docs/scripting/getting-started">Scripting documentation</a></li>
<li><a href="https://rive.app/blog/rive-ai-coding-agent-faq">AI Coding Agent FAQ</a></li>
<li><a href="https://rive.app/blog/why-scripting-runs-on-luau">Why Scripting runs on Luau</a></li>
<li><a href="https://www.youtube.com/watch?v=gIlCW5TRYw4">How to Build Dynamic Particle System in Rive Using Scripting &amp; AI Agent</a></li>
</ul>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Start building with Rive for iOS</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/68.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Part 3 of Start building with Rive for iOS]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue67</link>
            <guid>67</guid>
            <pubDate>Mon, 26 Jan 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, we're moving on to part 3, where we'll explore topics like rendering dynamic content and supporting multiple languages in Rive animations.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #67</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Last week, we carried on with our <strong>&quot;Start building with Rive for iOS&quot;</strong> series and wrapped up <strong>part 2</strong>.</p>
<blockquote>
<p>If you haven't had a chance to read it yet, I recommend <a href="/issue/issue66">checking it out</a> first to get the most value from the series.</p>
</blockquote>
<p>Now, we're moving on to <strong>part 3</strong>, where we'll explore topics like <strong>rendering dynamic content, supporting multiple languages in Rive animations, and efficiently managing assets</strong>.</p>
<h2>The Plan</h2>
<p>In this edition, I'll guide you through the mechanics of <strong>data binding with Rive View Models</strong>, show how to <strong>load and apply fonts</strong> to animations and explain how to implement <strong>fallback fonts</strong> that Rive can rely on when the main font lacks certain characters.
We'll follow this approach:</p>
<ul>
<li><a href="/issue/issue67-data-binding">🎸 Understanding data binding in Rive</a></li>
<li><a href="/issue/issue67-load-fonts">✍️ Loading and applying fonts to Rive animations</a></li>
<li><a href="/issue/issue67-fallback-fonts">🧘‍♀️ Adding Support for Fallback Fonts in Rive</a></li>
</ul>
<p>&lt;RenderRelatedWork
nextWorkUrl=&quot;/issue/issue67-data-binding&quot;
nextWorkTitle=&quot;🎸 Understanding Data Binding in Rive&quot;
/&gt;</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Start building with Rive for iOS</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/67.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Part 2 of Start building with Rive for iOS]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue66</link>
            <guid>66</guid>
            <pubDate>Mon, 19 Jan 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, we move to the part 2 of the series to explore how to build state-driven experiences with Rive on iOS.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #66</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Last week we kicked of the <a href="/issue/issue65">&quot;Start building with Rive for iOS&quot;</a> newsletter series.
This time, we move to the <strong>part 2</strong> of the series to explore how to build <strong>state-driven experiences</strong> with <strong>Rive</strong> on <strong>iOS</strong>.</p>
<h2>The Plan</h2>
<p>In this edition, I'll walk you through the fundamentals of <a href="https://rive.app/docs/runtimes/apple/apple">Rive's Apple runtime</a> library, show how to set up a <strong>RiveViewModel</strong> in both <strong>SwiftUI</strong> and <strong>UIKit</strong>, and wrap up this week's issue with a step-by-step build of a <strong>custom animated tab bar</strong> driven by <strong>Rive animations</strong>.
Below is the approach we'll follow:</p>
<ul>
<li><a href="/issue/issue66-swiftui">🏄🏻‍♂️ Getting started with Rive in SwiftUI</a></li>
<li><a href="/issue/issue66-uikit">🙌 Getting started with Rive in UIKit</a></li>
<li><a href="/issue/issue66-animated-tab-bar">🎮 Custom animated tab bar driven by Rive animations</a></li>
</ul>
<p>&lt;RenderRelatedWork
nextWorkUrl=&quot;/issue/issue66-swiftui&quot;
nextWorkTitle=&quot;🏄🏻‍♂️ Getting started with Rive in SwiftUI&quot;
/&gt;</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Start building with Rive for iOS</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/66.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🆕 Kicking Off a New Series on Rive for iOS ✅]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue65</link>
            <guid>65</guid>
            <pubDate>Mon, 12 Jan 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[My recent work experiences inspired me to start a new newsletter series titled 'Start building with Rive for iOS'. This is the 1st part of the series.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #65</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Recently, our design team at work has been advocating for the use of polished, fluid animations built with <a href="https://rive.app/">Rive</a>.
I happened to be the one tasked with exploring it, so I dove in, learning the tool, experimenting with it, and creating a few prototype projects along the way.</p>
<p>That inspired me to start a new series in the newsletter called <strong>&quot;Start building with Rive for iOS&quot;</strong> that I want to share with you!</p>
<p>The content is directly inspired by the challenges I faced integrating <strong>Rive</strong> into a production iOS app: <strong>state handling, view model coordination, dynamic asset configuration, performance considerations, and more.</strong></p>
<p>Each edition builds on the previous, moving from foundational concepts to more advanced, real-app use cases.
By the end of the series, we'll have put together a fully <strong>animated iOS app powered by Rive</strong>.</p>
<h2>Series Plan</h2>
<p>This will be a 4-part deep dive into using Rive on iOS.
Here's the high-level plan:</p>
<ul>
<li><strong>Edition 1 - Foundations &amp; App Narrative Setup</strong>
<ul>
<li>Introduction to Rive and its role in a modern SwiftUI/UIKit architecture</li>
</ul>
</li>
<li><strong>Edition 2 - State-Driven Experiences (SwiftUI + UIKit)</strong>
<ul>
<li>Getting started with Rive's Apple runtime</li>
<li>Implementing a RiveViewModel</li>
<li>Coordinating Rive State Machines with SwiftUI and UIKit state</li>
<li>Building a custom animated tab bar driven by Rive animations</li>
</ul>
</li>
<li><strong>Edition 3 - Dynamic Content, Localization, and Scalable Asset Strategy</strong>
<ul>
<li>Supporting multiple languages using Xcode String Catalogs and Rive bindings</li>
<li>Loading and applying fonts programmatically with the Rive iOS runtime, including fallback font support</li>
</ul>
</li>
<li><strong>Edition 4: Advanced Workflows with Rive Scripting + AI Agent</strong>
<ul>
<li>Creating a Rive Script that coordinates the animation layers and state machines</li>
<li>Improving animation logic using the AI coding agent</li>
<li>Integrating the script-driven animation into the app and connecting it with live data</li>
</ul>
</li>
</ul>
<h2>Rive Overview</h2>
<p><a href="https://rive.app/">Rive</a> is an interactive motion platform where you can code, design, and animate in one collaborative editor.
Instead of exporting frame-by-frame animations or videos, <strong>Rive</strong> uses vector graphics and state machines to create animations that can react instantly to user input and application state, while running them natively inside <strong>iOS</strong> apps.</p>
<p>In a modern <strong>iOS</strong> stack, <strong>Rive</strong> fits naturally alongside <strong>SwiftUI</strong> and <strong>UIKit</strong> as a dedicated layer for motion and interaction. Designers author animations and logic in the <a href="https://rive.app/editor">Rive editor</a>, export a single <code>.riv</code> file, and developers integrate it using one of the available <a href="https://rive.app/docs/runtimes/getting-started">Rive runtimes</a>.</p>
<blockquote>
<p>The next edition will cover more about the Apple runtime for iOS. Until then, feel free to take a look at the <a href="https://rive.app/docs/runtimes/apple/apple">documentation</a>.</p>
</blockquote>
<p>At runtime, animations are rendered efficiently using <strong>Metal</strong>, scale cleanly across device sizes, and can be driven directly from <strong>Swift</strong> code.</p>
<p>For <strong>SwiftUI</strong> apps, <strong>Rive</strong> works as an interactive view that can be bound to state, making animations a first-class part of a declarative UI.</p>
<p>In <strong>UIKit</strong>, <strong>Rive</strong> views integrate just like any other UIView, responding to gestures, control events, and view lifecycle changes.</p>
<blockquote>
<p>This makes Rive a strong complement to native iOS animations, handling complex, interactive motion while keeping <strong>SwiftUI and UIKit</strong> focused on layout, state, and navigation.</p>
</blockquote>
<h2>🤝 Wrapping Up</h2>
<p><strong>Rive</strong> brings together an interactive design platform, a powerful state-based graphics format, a lightweight cross-platform runtime, and an extremely fast rendering engine.</p>
<p>In the next edition, we'll move on to <strong>part 2</strong> of the series and explore how to build <strong>state-driven experiences with Rive on iOS</strong>.
Stay tuned!</p>
<p>Have a great week ahead 🤎</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Start building with Rive for iOS</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/65.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🎉 2025 Year-in-Review 📋]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue64</link>
            <guid>64</guid>
            <pubDate>Mon, 05 Jan 2026 09:20:00 GMT</pubDate>
            <description><![CDATA[As we kick off a new year, I'd like to take a moment to look back at 2025 and share a glimpse of what's ahead in 2026.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #64</strong> of the <strong>iOS Coffee Break Newsletter</strong> and to the first edition of <strong>2026</strong> 📬.</p>
<p>As we kick off a new year, I'd like to take a moment to look back at <strong>2025</strong> and share a glimpse of what's ahead in <strong>2026</strong>!
The past year has been both busy and fulfilling. I launched a brand-new app and continued documenting and sharing my learnings through newsletter editions.</p>
<p>Thank you for being part of the journey and for supporting my work throughout the year 🙏.</p>
<h2>Year Highlights</h2>
<p><strong>2025</strong> was a big year me:</p>
<ul>
<li><strong>23.7k</strong> unique visitors to the site.</li>
<li><strong>36</strong> newsletter issues were published.</li>
<li><strong>2</strong> new focused series covering popular iOS topics were released.</li>
<li>A new app, <a href="https://apps.apple.com/us/app/coffee-break-news/id6743022409">Coffee Break News</a>, was launched - built alongside the newsletter series &quot;Building a Newsletter App&quot;.</li>
</ul>
<h2>Top Issues</h2>
<ul>
<li><a href="https://www.ioscoffeebreak.com/issue/issue28">Bringing App Intents to Your SwiftUI App</a></li>
<li><a href="https://www.ioscoffeebreak.com/issue/issue41">Introducing Unit Tests with Swift Testing</a></li>
<li><a href="https://www.ioscoffeebreak.com/issue/issue50">Top WWDC Reads from the iOS Community</a></li>
<li><a href="https://www.ioscoffeebreak.com/issue/issue47">Creating an App Icon with Zero Design Skills</a></li>
<li><a href="https://www.ioscoffeebreak.com/issue/issue31">Using ImageRenderer in SwiftUI</a></li>
<li><a href="https://www.ioscoffeebreak.com/issue/issue62">Identifying Hangs in iOS Apps</a></li>
</ul>
<h2>What's coming in 2026</h2>
<p>This year will follow a similar rhythm to <strong>2025</strong>.
I'll continue publishing bi-weekly, writing about what I'm currently working on or iOS topics that catch my interest.</p>
<p>In 2025, <strong>AI</strong> features moved from &quot;nice demos&quot; to essential functionality. Because of that, I plan to commit some editions to <strong>AI-powered features using Apple Foundation Models</strong>.</p>
<p>I'll also keep expanding on topic-based series, starting from the basics and gradually increasing complexity.
A brand-new series is already in the works and I will kick it off next week (hopefully), so stay tuned! 💪</p>
<p>I'm also hoping to attend a conference later this year.
I attended <a href="/issue/issue17">Swift Leeds</a> toward the end of <strong>2024</strong>, and it was an experience I'd love to repeat, great connections and lots of learning.</p>
<h2>🤝 Wrapping Up</h2>
<p>Regarding the newsletter, I'm excited to keep the momentum going this year.
I'd also like to take this moment to sincerely <strong>thank you for your ongoing support</strong>, as well as last year's <strong>sponsors</strong>, whose contributions have made it possible for me to continue my mission of delivering free, high-quality content to the community.</p>
<p>Wishing you plenty of great coffee moments, and I hope to see you around this year 🤎</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/64.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🩺 Analysing and Removing Hangs in iOS Apps 🧞‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue63</link>
            <guid>63</guid>
            <pubDate>Mon, 15 Dec 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week we will pick up where we left off with the same demo app and take a closer look at what is triggering the blockage.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #63</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>In <a href="/issue/issue62">last week's edition</a>, I guided you through the process of <strong>analyzing app hangs using Instruments</strong> 😰.</p>
<p>This week, we will pick up where we left off with the same demo app.
I have intentionally included code that blocks the main thread, and we will take a closer look at what is triggering the blockage.</p>
<p>We will also explore how to <strong>pinpoint the specific functions in our code that can be optimized to eliminate the hang!</strong></p>
<blockquote>
<p>This guide was created using Xcode 16.4, but all instructions should remain current for Xcode 26.</p>
</blockquote>
<h3>Determining whether the Main Thread is Busy or Blocked</h3>
<p>Once we have identified the hang, the next step is to check how much CPU the main thread is using:</p>
<ul>
<li>If the CPU usage is high, it suggests that the main thread is doing a lot of work.</li>
<li>On the other hand, low CPU usage typically indicates that the main thread is probably blocked.</li>
</ul>
<p>When you notice high CPU usage during the hang, we should investigate the tasks running on the main thread.
But if the usage is low, it is more effective to focus on understanding what is preventing the thread from running, rather than what it is doing.</p>
<blockquote>
<p>Explore <a href="https://developer.apple.com/tutorials/instruments">Apple's Instruments tutorials</a> to learn how to enhance app responsiveness, minimize memory consumption, and examine complex performance patterns over time.</p>
</blockquote>
<p>&lt;StaticImage
src=&quot;/issues/issue63/main-thread-busy-or-blocked.webp&quot;
alt=&quot;Unresponsive Main Thread picture from Apple Instruments Tutorials.&quot;
link=&quot;/issues/issue63/main-thread-busy-or-blocked.webp&quot;
caption=&quot;Unresponsive Main Thread picture from Apple Instruments Tutorials.&quot;
/&gt;</p>
<p>To check this in <strong>Instruments</strong>, expand the <code>HangApp</code> track by clicking the small triangle to reveal its subtracks.
Then, right-click on the <code>&quot;Severe Hang&quot;</code> segment in any track and select <code>&quot;Set Inspection Range&quot;</code> from the menu.</p>
<p>After that, click on the <code>Main Thread</code> track to highlight it.</p>
<blockquote>
<p>The main thread is the most important thread for analyzing hangs. Instruments displays it at the top.</p>
</blockquote>
<p>&lt;StaticImage
src=&quot;/issues/issue63/cpu-trace.webp&quot;
alt=&quot;Analysing the CPU Usage Trace.&quot;
link=&quot;/issues/issue63/cpu-trace.webp&quot;
caption=&quot;Analysing the CPU Usage Trace.&quot;
/&gt;</p>
<p>By examining the CPU Usage graph for the main thread during the hang, we can see that the CPU activity is minimal.
<strong>This tells us that this is a blocked main thread hang.</strong></p>
<p>The next step is to determine what is causing this blockage.</p>
<h3>Enabling the Thread State Trace</h3>
<p>To identify the root cause effectively, it is important to observe thread behavior in detail:</p>
<p>In Instruments, add the <strong>Thread State Trace</strong> tool by selecting it in the Instruments panel (<strong>+ Instrument</strong> &gt; Type <strong>&quot;Thread State Trace&quot;</strong>).
This visualization will help reveal which threads are blocked or excessively busy.</p>
<p>Since there isn't an existing Thread State Trace graph, we will need to run the Instruments again and reproduce the same scenario.
After stopping the recording, Xcode will process the data and display the graph within Instruments, making it easier to analyze and resolve the issue.</p>
<h3>Identifying Relevant Functions</h3>
<p>The app hang is caused by intensive operations running on the main thread, which interferes with UI rendering and blocks user interaction.
By leveraging Thread State Trace and carefully inspecting a specific portion of the timeline, we can trace the issue back to the function responsible for the hang, as illustrated in the image below:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue63/thread-state-trace.webp&quot;
alt=&quot;Analysing the Tread State Trace.&quot;
link=&quot;/issues/issue63/thread-state-trace.webp&quot;
caption=&quot;Analysing the Tread State Trace.&quot;
/&gt;</p>
<p>Upon reviewing the Thread State Trace graph and associated logs, here is what it is telling us:</p>
<ul>
<li>The Instruments timeline clearly highlights a significant hang in the &quot;Hangs&quot; section.
During this period, the main thread was unresponsive, unable to handle inputs or refresh the UI.
The call stack leads us to the <code>IssueRowView.init(issue:)</code> method, where some resource-heavy task or delay occurred directly on the main thread, making the app stall.</li>
<li>A key observation is a recorded hang lasting <strong>501 milliseconds</strong>, aligning with a simulated delay introduced using <code>Thread.sleep(forTimeInterval: 0.5)</code> inside the <code>IssueRowView.init(issue:)</code> initializer.
This confirms that this method is a primary contributor to the performance issue.</li>
</ul>
<p>Below is the section of code that causes the thread blockage:</p>
<pre><code class="language-swift">struct IssueRowView: View {
    let issue: Issue

    init(issue: Issue) {
        self.issue = issue
        // introduced an intentional delay that blocks the main thread
        Thread.sleep(forTimeInterval: 0.5)
    }

    var body: some View {
        [...]
    }
}
</code></pre>
<h3>Fixing the Hang</h3>
<p>As a straightforward demonstration, offloading the task to a <strong>background thread</strong> provides a quick and effective solution to eliminate the hang.
Below is the revised <code>init</code> method:</p>
<pre><code class="language-swift">struct IssueRowView: View {
    let issue: Issue

    init(issue: Issue) {
        self.issue = issue

        DispatchQueue.global(qos: .background).async {
            // Perform heavy computation on a background thread
            Thread.sleep(forTimeInterval: 0.5)
        }
    }

    var body: some View {
        [...]
    }
}
</code></pre>
<p>With this change in place, running the app again will show no hangs detected in Instruments, confirming that the issue has been resolved! 💪</p>
<p>&lt;StaticImage
src=&quot;/issues/issue63/green-trace.webp&quot;
alt=&quot;CPU Usage Trace Graph after offloading the task to a background thread.&quot;
link=&quot;/issues/issue63/green-trace.webp&quot;
caption=&quot;CPU Usage Trace Graph after offloading the task to a background thread.&quot;
/&gt;</p>
<p>This example highlights how crucial it is to perform heavy computations on a background thread to maintain responsive UI updates and prevent major freezes!</p>
<blockquote>
<p>To explore the full implementation of the sample hang application, visit the <a href="https://github.com/henriquestiagoo/HangApp/tree/fixing-hang">repository</a> on GitHub.</p>
</blockquote>
<h2>🤝 Wrapping Up</h2>
<p><strong>Understanding the activity on the main thread is crucial to identify and address app hangs</strong>, which is vital for delivering a smooth user experience.
For this, we can use tools such as Instruments to pinpoint performance issues.
<strong>Make sure intensive tasks run on background threads, and reserve the main thread exclusively for UI updates.</strong></p>
<p>Following these best practices will help you create fast, responsive, and well-performing iOS apps!</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>Have a great week ahead 🤎</p>
<h2>References</h2>
<ul>
<li><a href="https://developer.apple.com/tutorials/instruments/analyzing-main-thread-activity">Analysing main thread activity</a></li>
<li><a href="https://developer.apple.com/tutorials/instruments/reducing-main-thread-work-by-doing-less">Reducing main thread work by doing less</a></li>
<li><a href="https://developer.apple.com/tutorials/instruments/executing-work-asynchronously">Executing work asynchronously</a></li>
<li><a href="https://developer.apple.com/tutorials/instruments/ensuring-work-executes-in-a-background-thread">Ensuring work executes on a background thread</a></li>
</ul>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>UI Hang</category>
            <category>Instruments</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/63.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👮‍♂️ Identifying Hangs in iOS Apps 😰]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue62</link>
            <guid>62</guid>
            <pubDate>Mon, 01 Dec 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this week's issue, we will dive into a common performance challenge in iOS apps: UI hangs caused by intensive tasks running on the main thread.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #62</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>In this week's issue, we will dive into a common performance challenge in iOS apps: <strong>UI hangs caused by intensive tasks running on the main thread</strong> 🥵.</p>
<p>We will also walk through how to <strong>analyze these hangs using Instruments</strong>.
To illustrate this, I have put together a demo app with deliberately added code that causes the main thread to block.
The app mimics a <strong>GET</strong> request to retrieve a list of newsletter's editions.</p>
<blockquote>
<p>This guide was created using Xcode 16.4, but all instructions should remain current for Xcode 26.</p>
</blockquote>
<h3>What is a Hang?</h3>
<p>A <strong>UI hang</strong> occurs when the app's interface stops responding for a noticeable amount of time.
This typically results from long-running operations that occupy the main thread, which is responsible for updating the UI and processing user input.</p>
<blockquote>
<p>Apple strongly recommends avoiding heavy processing on the main thread.
Instead, these operations should be delegated to background threads.</p>
</blockquote>
<h2>The Plan</h2>
<p>In this edition, the plan is to simulate blocking the main thread with heavy computations, leading to a UI hang.
Here is a quick summary:</p>
<ul>
<li>Simulating a UI Hang</li>
<li>Identifying the Hang using Instruments</li>
</ul>
<h3>Experiencing a Hang</h3>
<p>The demo app includes two tabs: About and Issues.
The hang occurs when navigating to the Issues tab.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue62/hang-sample.gif&quot;
alt=&quot;Experiencing a UI Hang.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue62/hang-sample.gif&quot;
caption=&quot;Experiencing a UI Hang.&quot;
priority={true}
/&gt;</p>
<p>We'll notice that tapping on the Issues tab doesn't trigger an immediate response.
It takes about <strong>4 seconds</strong> for the app to react before it displays several rows of issues.</p>
<p>During this delay, not only is the Issues tab inactive, but the entire app becomes unresponsive.
We can't interact with any part of the UI until the content finally loads.</p>
<h3>Detecting a UI Hang using Instruments</h3>
<p>In Xcode, press and hold the <code>Run</code> button, then select <code>Profile</code> from the dropdown menu.</p>
<blockquote>
<p>Alternatively, we can start profiling by navigating to Product &gt; Profile or using the shortcut (Command-I).</p>
</blockquote>
<p>Once Xcode finishes building our app, it will launch Instruments with your app as the target.
From the list of available templates, choose <code>Time Profiler</code>, then click <code>Choose</code> to proceed.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue62/instruments.webp&quot;
alt=&quot;Opening Instruments in Xcode.&quot;
link=&quot;/issues/issue62/instruments.webp&quot;
caption=&quot;Opening Instruments in Xcode.&quot;
/&gt;</p>
<p>This will open a new Instruments session, preloaded with tools commonly used for analyzing time-based performance issues.</p>
<h3>Recording a Session</h3>
<p>Start by clicking the <code>Record</code> button to begin recording data.
Instruments will launch your app and begin tracking its activity.</p>
<p>To reproduce the issue, tap on the Issues tab in the app once again.
After the hang is over, stop recording.</p>
<p>&lt;StaticGIF
src=&quot;/issues/issue62/recording-session.gif&quot;
alt=&quot;Recording a session on Instruments.&quot;
link=&quot;/issues/issue62/recording-session.gif&quot;
caption=&quot;Recording a session on Instruments.&quot;
/&gt;</p>
<blockquote>
<p>A large red rectangle will appear in the Hangs track, marking when the freeze began and how long it lasted.</p>
</blockquote>
<h3>Zooming to Inspection Range</h3>
<p>Next, go to <code>View</code> &gt; <code>Zoom</code> &gt; <code>Zoom to Inspection Range</code> to narrow in on the relevant portion of the timeline.</p>
<p>Hover your cursor over the red block in the Hangs track to view a tooltip showing the precise length of the freeze.
Here, we can see that the hang duration was almost <strong>4 seconds</strong> - a <strong>Severe Hang</strong>.</p>
<p>&lt;StaticGIF
src=&quot;/issues/issue62/zooming-view.gif&quot;
alt=&quot;Zooming to Inspection Range on Instruments.&quot;
link=&quot;/issues/issue62/zooming-view.gif&quot;
caption=&quot;Zooming to Inspection Range on Instruments.&quot;
/&gt;</p>
<h2>🤝 Wrapping Up</h2>
<p>In this chapter, we successfully simulated a <strong>UI hang</strong>, experienced how it <strong>affects app responsiveness, and gained a better understanding of its impact on the user experience</strong>.
We also <strong>captured the hang using Instruments</strong>, allowing us to measure its duration and prepare for deeper analysis.</p>
<p>With the hang now identified, the next step is to <strong>investigate how much CPU activity is happening on the main thread</strong>.
If the CPU usage is high, it suggests the main thread is overwhelmed with tasks; if it is low, the thread might be blocked entirely.</p>
<p>Sounds like a solid focus for next newsletter's edition, right? 🤔</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<blockquote>
<p>Here is the <a href="https://github.com/henriquestiagoo/HangApp/tree/identifying-hangs">GitHub repository</a> link if you are interested.</p>
</blockquote>
<p>Have a great week ahead 🤎</p>
<h2>References</h2>
<ul>
<li><a href="https://developer.apple.com/tutorials/instruments/identifying-a-hang">Identifying a hang</a></li>
</ul>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>UI Hang</category>
            <category>Instruments</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/62.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🎃 Happy Halloween, iOS creators! 👻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue61</link>
            <guid>61</guid>
            <pubDate>Mon, 03 Nov 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[Now that the spooky season has come and gone, it's the perfect time to reveal some frighteningly useful iOS tips, tricks, and treats!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #61</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Now that the spooky season has come and gone, it's the perfect time to reveal some frighteningly useful iOS tips, tricks, and treats 👻 !
Here in Portugal 🇵🇹, Halloween is slowly gaining more magic each year, but I would love to know how you celebrate it where you are!</p>
<p>Do your countries light up with costumes and candy, or keep things cozy, spooky and mysterious?</p>
<p>Let's start a new trend! Share your Halloween traditions on social media with the hashtag <code>#iosspookyseason</code> 🕯️🍬</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://x.com/Jchammond_/status/1977965883055366379">🤖 How to write better prompts when building iOS apps</a></h2>
<p><a href="https://x.com/Jchammond_">Connor</a> recently shared a great video on what makes an effective prompt when building iOS apps with AI.
He walked through an example of creating a speech journaling app using ChatGPT, showing how the quality of your prompt can make all the difference.</p>
<p>By comparing a vague, unstructured prompt with a clear, detailed one, Connor highlighted just how much stronger and more tailored the results can be when you give AI the right context.</p>
<p>If you are experimenting with AI in your apps, take a moment to be intentional with your prompts.
A little clarity upfront goes a long way, saving you time, frustration, and plenty of unnecessary rework later on.</p>
<h2><a href="https://www.youtube.com/shorts/fCvy5hyXa9U">🎬 Trying out something new, sharing a glimpse into my life as an iOS engineer in Copenhagen </a></h2>
<p>Last week, I came across a tweet from <a href="https://x.com/monika_mateska">Monika</a> sharing what a typical Friday looks like for her as an iOS Engineer in Copenhagen, working at Vivino, and I instantly knew it deserved a spot here in the newsletter.</p>
<p>It got me thinking ... how do you usually spend your days as an iOS dev? 🤔
All I know is, I definitely go through way more cups of coffee than I should! ☕️</p>
<h2><a href="https://www.youtube.com/@swiftleeds/videos">🔥 SwiftLeeds Day One Videos Are Live!</a></h2>
<p>A few days ago, <a href="https://x.com/Adam9Rush">Adam</a> shared that the day-one sessions from the <strong>SwiftLeeds</strong> Conference are now live on their YouTube channel!
The talks feature fantastic insights from an incredible lineup of speakers, covering everything from advanced Swift techniques to real-world app development experiences.</p>
<p>Whether you made it to the conference or not, these sessions are packed with gems for iOS developers at any level. Definitely worth a watch!</p>
<h2><a href="https://www.swift.org/blog/nightly-swift-sdk-for-android/">⬆️ Announcing the Swift SDK for Android</a></h2>
<p>Over the past years, <strong>Swift</strong> has evolved tremendously, expanding its reach from cloud-based solutions to Windows programs, web apps, and even microcontrollers.</p>
<p>Exciting update from last week! Sharing code between iOS and Android is now far simpler! If you are building apps for both platforms, you might want to explore the new <strong>Swift SDK available for Android</strong>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Community</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/61.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👋 In Case You Missed It (Community Edition) 🙆‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue60</link>
            <guid>60</guid>
            <pubDate>Mon, 13 Oct 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I didn't have the chance to focus on the upcoming series I have been preparing, but I still wanted to share a few articles and updates that caught my attention.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #60</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>This week, I didn't have the chance to focus on the upcoming series I have been preparing 🤩, but I still wanted to share a few articles and updates that caught my attention.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://livsycode.com/swift/detecting-text-language-with-nllanguagerecognizer-in-swift/">🕵🏻‍♂️ Detecting Text Language with NLLanguageRecognizer in Swift</a></h2>
<p>This week, I discovered that Apple's <a href="https://developer.apple.com/documentation/naturallanguage">NaturalLanguage</a> framework offers an easy and effective method for <strong>identifying the primary language of a given text</strong>.</p>
<p>In <a href="https://x.com/livsycode">Artem's</a> latest article, you can see it in practice. He explains how <code>NLLanguageRecognizer</code> functions, explores its limitations, and presents a reusable <code>LanguageDetector</code> implementation in Swift.</p>
<h2><a href="https://www.swifttoolkit.dev/posts/lambda-v2">🆕 What's New in the Lambda V2 Runtime</a></h2>
<p>The Swift AWS Lambda Runtime V2 is now officially out of beta with version <a href="https://github.com/swift-server/swift-aws-lambda-runtime/releases/tag/2.0.0">2.0.0</a>!</p>
<p>The update introduces several new capabilities including background execution for improved performance, streaming responses for real-time applications, and more.
Be sure to check out <a href="https://x.com/SwiftToolkit">Swift Toolkit's</a> latest article and explore the sample project to see it in action!</p>
<h2><a href="https://brightinventions.pl/blog/certificate-pinning-in-ios-app/">⛔️ Certificate Pinning on iOS in Practice</a></h2>
<p>This week, I came across an insightful article by Tomasz, from <a href="https://x.com/BrightDevs">Bright Inventions</a> about <strong>certificate pinning on iOS</strong>, and I wanted to share it since it is such a relevant topic in software development.</p>
<p>You have probably heard of <strong>man-in-the-middle</strong> attacks, but if you are new to the concept, or just want a quick refresher, this article is definitely worth a read.</p>
<h2><a href="https://streamyard.com/ik659maf7b32">​🎥 CI/CD for iOS Developers webinar recording</a></h2>
<p>Last week, <a href="https://x.com/polpielladev">Pol</a> hosted a <strong>free</strong> webinar for subscribers of the iOS CI Newsletter, covering the essentials of <strong>getting started with CI/CD</strong> and building a release pipeline for an iOS app from the ground up.</p>
<p>If you missed the live session or haven't had the chance to watch it yet, you can catch the recording. It is definitely worth it!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Community</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/60.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👩‍🔬 Testing Swift CLI Tools with GitHub Actions 🧪]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue59</link>
            <guid>59</guid>
            <pubDate>Mon, 06 Oct 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I decided to set up a workflow to run my command-line tool tests using GitHub Actions.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #59</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Hello all 👋! I know, I know! The past few weeks have been busy for me, and I haven't been able to write as often as I'd hoped. But this week, we are back on track!</p>
<p>I also want to take this chance to let you know that the newsletter will be shifting from a <strong>weekly</strong> schedule to a more occasional, likely <strong>bi-weekly</strong> or <strong>monthly</strong>.
I have some new opportunities coming up, which means I'll have less time to focus to writing.
That said, let's dive right into this week's topic!</p>
<p>If you have been keeping up with the newsletter, you probably know I have been working on a <a href="/issue/issue57">command-line tool that generates dummy data 🛠</a>.
In a previous edition, I explained how I <a href="/issue/issue58">automated its release process using GitHub Actions</a>.</p>
<p>As part of my learning on <strong>GitHub Actions</strong>, I recently set up a workflow to <strong>run tests for the CLI tool</strong>.
This week, I would like to walk you through that process and what I learned!</p>
<h2>The Plan</h2>
<p>In this edition, my plan was to set up a <strong>GitHub Actions workflow to run tests for my command-line tool</strong>.
Here is what I wanted the workflow to do:</p>
<ul>
<li>Trigger automatically on any <strong>push</strong> or <strong>pull request</strong> to the repository main branch.</li>
<li><strong>Run Tests</strong> on a macOS environment.</li>
</ul>
<h3>Setting Up the Test Workflow</h3>
<p>First, we need to add a workflow file in the <code>.github/workflows</code> directory.
If that folder doesn't exist yet, go ahead and create it.</p>
<pre><code class="language-bash">$ mkdir -p .github/workflows
$ touch .github/workflows/test.yml
</code></pre>
<h3>Writing the GitHub Workflow</h3>
<p>The next step is to define our workflow:</p>
<pre><code class="language-bash">name: Run Tests

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

jobs:
  macos-test:
    name: Test on macOS
    runs-on: macOS-15
    timeout-minutes: 30
    env:
      DEVELOPER_DIR: /Applications/Xcode_16.2.app
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Run unit tests on macOS for Swift Package
        run: |
          set -o pipefail &amp;&amp; xcodebuild -scheme SwiftDummyGen-Package \
            -destination &quot;platform=macOS&quot; test | xcpretty
</code></pre>
<p>Here is a quick overview of what the workflow does:</p>
<ul>
<li>It is triggered whenever code is pushed to the main branch or a pull request is opened targeting it.</li>
<li>The first step uses the checkout action to pull the latest version of the code from the repository so it can be tested.</li>
<li>We use <code>xcodebuild</code> to execute the tests. The <code>-scheme</code> option tells it which scheme to build and test while the <code>-destination</code> flag sets the target environment. In this case, macOS.</li>
<li>In the end, we pipe the output through <code>xcpretty</code> to make the results cleaner and easier to read.</li>
</ul>
<p>&lt;StaticImage
src=&quot;/issues/issue59/test-action.webp&quot;
alt=&quot;The output of the CLI tests.&quot;
link=&quot;/issues/issue59/test-action.webp&quot;
caption=&quot;The output of the CLI tests.&quot;
/&gt;</p>
<h2>🤝 Wrapping Up</h2>
<p>Using <strong>GitHub Actions</strong> to <strong>automate iOS testing</strong> simplifies our workflow by identifying issues early and frequently.
This issue outlines a simple configuration that can serve as a foundation for more advanced setups, like testing across <strong>different simulators</strong> or <strong>incorporating UI tests</strong>.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CI/CD</category>
            <category>GitHub Actions</category>
            <category>Tests</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/59.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🤖 Automating Swift Binary Releases Using GitHub Actions 📦]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue58</link>
            <guid>58</guid>
            <pubDate>Mon, 01 Sep 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this edition, I walk you through setting up a GitHub Actions workflow that automatically builds and publishes your Swift CLI tools whenever a new tag is pushed to your repo.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #58</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>In last week's edition, I shared a <a href="/issue/issue57">Swift CLI tool that generates mock data from a Swift struct 🛠</a>.</p>
<p>This week, I explored ways to automate the release pipeline for that command-line utility using <strong>GitHub Actions</strong>.</p>
<blockquote>
<p>Although the project isn't open-sourced yet, it is worth noting that GitHub provides unlimited free CI/CD minutes for public repositories, making it an ideal choice for open-source development workflows 🤩.</p>
</blockquote>
<h2>The Plan</h2>
<p>For this edition, I wanted to automate the release process of my dummy generator tool.
The goal is to write a <strong>GitHub workflow</strong> that:</p>
<ul>
<li>Triggers automatically upon pushing a new tag in the repository.</li>
<li>Compiles and compresses the binary on a macOS runner.</li>
<li>Uploads the resulting executable to the release page.</li>
</ul>
<h3>Setting Up the Release Workflow</h3>
<p>To get started with <strong>GitHub Actions</strong>, we will need to create a new workflow file inside our repo's <code>.github/workflows</code> directory.</p>
<pre><code class="language-bash">$ mkdir -p .github/workflows
$ touch .github/workflows/release.yml
</code></pre>
<h3>Writing the GitHub Workflow Action</h3>
<p>The next step is to define our workflow:</p>
<pre><code class="language-bash">name: Create Mac Release

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:
  release-macos:
    name: Release macOS Executable
    runs-on: macos-15 

    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Build executable for release
        run: swift build -c release --arch arm64 --arch x86_64 --product SwiftDummyGen
      - name: Compress executable
        run: |
          BUILD_PATH=$(swift build -c release --arch arm64 --arch x86_64 --product SwiftDummyGen --show-bin-path)
          cp &quot;$BUILD_PATH/SwiftDummyGen&quot; SwiftDummyGen
          tar -czf ${{ github.ref_name }}.tar.gz -c SwiftDummyGen
      - name: Upload binaries to release
        uses: svenstaro/upload-release-action@v2
        with:
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ github.ref_name }}.tar.gz
          tag: ${{ github.ref }}
          overwrite: true
</code></pre>
<p>Here is a breakdown of what is happening behind the scenes:</p>
<ul>
<li>We have configured the workflow to trigger on push events, specifically when a version tag following the pattern <code>(v*.*.*)</code> is pushed to the repository.</li>
<li>To make the tool available for use, it needs to be compiled for the desired platforms. In this case, both macOS <strong>arm64</strong> and <strong>x86_64</strong>.</li>
<li>After building the binaries, we set up a GitHub release that uses the pushed tag as its identifier and included a compressed archive containing the compiled binaries.</li>
<li>As illustrated in the workflow above, we can use <a href="https://github.com/svenstaro/upload-release-action">svenstaro's upload-release-action</a> to generate the release on GitHub.</li>
<li>Be sure to commit this workflow file to your repository so it can run properly.</li>
</ul>
<h3>Adding Permissions to the Workflow</h3>
<p>Before running the workflow, there is an important detail. In order to commit changes, the workflow needs to have write access.</p>
<p>To enable it, go to the repository settings, and under Actions, look for <code>Workflow Permissions</code>. Then, select <code>Read and Write Permissions</code>, and save it.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue58/write-permissions.webp`&quot;
alt=&quot;Set write permissions to the GitHub action.&quot;
src=&quot;/issues/issue58/write-permissions.webp&quot;
caption=&quot;Set write permissions to the GitHub action.&quot;
/&gt;</p>
<h3>Tagging a Release</h3>
<p>We can create and push a new version tag directly from the terminal by running the following commands:</p>
<pre><code class="language-bash">$ git tag v1.0.0        
$ git tag    
$ git push origin v1.0.0
</code></pre>
<h3>Executing the Workflow</h3>
<p>After a few moments, the workflow completes its run successfully!</p>
<p>&lt;StaticImage
src=&quot;/issues/issue58/completed-action.webp&quot;
alt=&quot;The action has completed successfully!&quot;
link=&quot;/issues/issue58/completed-action.webp&quot;
caption=&quot;The action has completed successfully!&quot;
/&gt;</p>
<p>We will find our compiled binary available as an asset on the release page! 🥳</p>
<p>&lt;StaticImage
src=&quot;/issues/issue58/release.webp&quot;
alt=&quot;We can find our binary in the release assets.&quot;
link=&quot;/issues/issue58/release.webp&quot;
caption=&quot;We can find our binary in the release assets.&quot;
/&gt;</p>
<h2>🤝 Wrapping Up</h2>
<p>In this edition, I walked you through setting up a <strong>GitHub Actions workflow</strong> that automatically <strong>builds and publishes your Swift command-line tools</strong> whenever a new tag is pushed to your repo.</p>
<p>Have a great week ahead 🤎</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CI/CD</category>
            <category>GitHub Actions</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/58.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🛠 Creating a Dummy Data Generator CLI tool using Swift Package Manager 📦]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue57</link>
            <guid>57</guid>
            <pubDate>Mon, 25 Aug 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I put together a step-by-step guide on building a command-line tool for generating dummy data using Swift Package Manager.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #57</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>One <strong>recurring task</strong> I often find myself doing is <strong>generating dummy data</strong>, both in work-related and personal projects.
While it is not particularly time-consuming, it is something <strong>I can automate to save a significant amount of time down the road</strong>.</p>
<p>So, this week, I put together a guide on <strong>building a command-line tool</strong> for generating dummy data using the <strong>Swift Package Manager</strong>.
With SPM, creating CLI tools becomes much simpler, especially since we can build them directly in Swift.</p>
<h2>The Plan</h2>
<p>The plan is simple: implement a command line tool that generates dummy data from a Swift <code>struct</code>.
Here is the approach:</p>
<ul>
<li><strong>CLI tool</strong> written in <strong>Swift</strong>.</li>
<li>Use <a href="https://github.com/apple/swift-argument-parser">ArgumentParser</a> for:
<ul>
<li><strong>input file</strong>: <code>.swift</code> file with a <code>struct</code>.</li>
<li><strong>count</strong>: number of dummy instances to generate (with a default value of 5).</li>
<li><strong>output file</strong>: path to Swift file for writing results.</li>
</ul>
</li>
<li>Parsing a <strong>single struct</strong>.</li>
<li>The struct fields are limited to <strong>primitive</strong> types: <strong>String, Int, Double, Bool, Date</strong>.</li>
<li><strong>No nesting or recursive</strong> generation (maybe in the future).</li>
</ul>
<h2>Creating a command-line tool using SPM</h2>
<p>First, we need to create a <strong>Swift</strong> executable. To create a new project, run the following in your terminal:</p>
<pre><code class="language-bash">$ mkdir SwiftDummyGen
$ cd SwiftDummyGen
$ swift package init --type executable
</code></pre>
<p>&lt;StaticImage
src=&quot;/issues/issue57/tool-init.webp&quot;
alt=&quot;Creating a command-line tool&quot;
link=&quot;/issues/issue57/tool-init.webp&quot;
caption=&quot;Creating a command-line tool.&quot;
/&gt;</p>
<p>Running the init command sets up a new package in your current directory.
This includes generating a <code>Package.swift</code> file, where you can define your dependencies and additional targets, as well as a <code>main.swift</code> file, which serves as the primary script.
We can rename <code>main.swift</code> and designate it as the entry point using the <code>@main</code> attribute.</p>
<pre><code class="language-swift">@main
struct SwiftDummyGen {
    static func main() {
        print(&quot;Your command line tool starts here!&quot;)
    }
}
</code></pre>
<h3>Adding the ArgumentParser framework for reading user input</h3>
<p>Most command-line applications need to handle input from the user via arguments, and this tool is no different.
To enable argument parsing, we will include the <a href="https://github.com/apple/swift-argument-parser">swift-argument-parser</a> package as a dependency.</p>
<p>To integrate it, simply update your <code>Package.swift</code> file with the necessary configuration.</p>
<pre><code class="language-swift">import PackageDescription

let package = Package(
    name: &quot;SwiftDummyGen&quot;,
    platforms: [
        .macOS(.v15)
    ],
    dependencies: [
        .package(url: &quot;https://github.com/apple/swift-argument-parser&quot;, from: &quot;1.5.0&quot;),
        [...]
    ],
    targets: [
        .executableTarget(
            name: &quot;SwiftDummyGen&quot;,
            dependencies: [
                .product(name: &quot;ArgumentParser&quot;, package: &quot;swift-argument-parser&quot;),
                [...]
            ]
        )
    ]
)
</code></pre>
<h3>Setting Up Property Wrappers</h3>
<p>The <code>SwiftDummyGen</code> structure adopts the <a href="https://apple.github.io/swift-argument-parser/documentation/argumentparser/parsablecommand/">ParsableCommand</a> protocol, which lets us configure the command with a brief description.</p>
<p>To handle user input, we use three kinds of property wrappers:</p>
<ul>
<li><strong>Argument</strong>: A mandatory value the subcommand requires to run.</li>
<li><strong>Option</strong>: An optional input that can be provided by the user.</li>
<li><strong>Flag</strong>: A toggle that influences how the command behaves.</li>
</ul>
<pre><code class="language-swift">@main
struct SwiftDummyGen: ParsableCommand {
    @Argument(help: &quot;The input Swift file with the struct definition.&quot;)
    var input: String

    @Option(name: .shortAndLong, help: &quot;The number of dummy elements to generate.&quot;)
    var count: Int = 5

    @Option(name: .shortAndLong, help: &quot;Writes the output to a Swift file rather than to standard output.&quot;)
    var output: String?

    static var configuration: CommandConfiguration {
        CommandConfiguration(
            commandName: &quot;SwiftDummyGen&quot;,
            abstract: &quot;Generates dummy data from your Swift structs.&quot;
        )
    }

    func run() throws {
        [...]

        if let output = output {
            try outputString.write(toFile: output, atomically: true, encoding: .utf8)
            print(&quot;✅ Generated dummy data written to \(output).&quot;)
        } else {
            print(&quot;\n\(outputString) \n\n✅ Generated dummy data written to standard output.&quot;)
        }
    }
}
</code></pre>
<blockquote>
<p>I have intentionally skipped over the implementation specifics, as the goal here is to outline the essential steps for creating a Swift-based CLI tool.</p>
</blockquote>
<h3>Using Our Swift CLI Tool</h3>
<p>At this point, we can start using our command-line tool and see what it does.</p>
<pre><code class="language-bash">$ swift run SwiftDummyGen --help
</code></pre>
<p>&lt;StaticImage
src=&quot;/issues/issue57/tool-help.webp&quot;
alt=&quot;The output of the tool help command.&quot;
link=&quot;/issues/issue57/tool-help.webp&quot;
caption=&quot;The output of the tool help command.&quot;
/&gt;</p>
<p>One of the advantages of using the <strong>ArgumentParser</strong> framework is that it handles much of the heavy lifting for us.
It automatically creates descriptive output similar to what we would expect from other CLI utilities.
It also includes a built-in help flag, which is a standard feature in most command-line applications.</p>
<h3>🧪 Example Usage</h3>
<p>Say our input file is <code>input.swift</code> which contains the definition of a struct named <code>Issue</code>:</p>
<pre><code class="language-swift">struct Issue {
    var id: String
    var content: String
    var url: String
    var title: String
    var summary: String
    var date: Date
}
</code></pre>
<h3>Running the tool</h3>
<p>Our command-line tool is ready to be used. Just run the following command in your terminal:</p>
<pre><code class="language-bash">$ swift run SwiftDummyGen input.swift --count 2 --output output.swift
</code></pre>
<p>This generates 2 dummy issues instances and writes them to <code>output.swift</code>.</p>
<pre><code class="language-swift">// Auto-generated by SwiftDummyGen.
import Foundation

struct Issue {
    var id: String
    var content: String
    var url: String
    var title: String
    var summary: String
    var date: Date
}

let dummyIssueData: [Issue] = [
    Issue(
        id: &quot;Sample 345&quot;, 
        content: &quot;Sample 745&quot;, 
        url: &quot;Sample 692&quot;, 
        title: &quot;Sample 871&quot;, 
        summary: &quot;Sample 579&quot;, 
        date: Date(timeIntervalSinceNow: 2776)
    ),
    Issue(
        id: &quot;Sample 310&quot;, 
        content: &quot;Sample 362&quot;, 
        url: &quot;Sample 213&quot;, 
        title: &quot;Sample 309&quot;, 
        summary: &quot;Sample 18&quot;, 
        date: Date(timeIntervalSinceNow: -221)
    )
]
</code></pre>
<blockquote>
<p>The output property is optional. If it not passed, our tool will print out the results in the terminal.</p>
</blockquote>
<h3>Compiling as Executable</h3>
<p>To turn your target into an executable, use the <code>build</code> command:</p>
<pre><code class="language-bash">$ swift build
</code></pre>
<p>Once we have set up our command-line tool, the next step is to compile it for actual use.
We can achieve this by building it in release mode using the <strong>-c</strong> release flag.
This will generate an executable located in the <code>.build/release</code> directory.</p>
<pre><code class="language-bash">$ swift build -c release
</code></pre>
<p>If you are curious about the exact path of the compiled binary, here is how you can find it:</p>
<pre><code class="language-bash">$ swift build -c release --show-bin-path
</code></pre>
<p>To actually make use of it, we need to copy it over into the <code>/usr/local/bin</code> folder.
Here is how we can do it:</p>
<pre><code class="language-bash">$ cp -f .build/release/SwiftDummyGen /usr/local/bin/SwiftDummyGen
</code></pre>
<p>That should be enough to make our CLI tool available as a real tool!</p>
<p>We can now run <code>SwiftDummyGen</code> using your CLI tool from within any folder from the terminal! 🥳</p>
<pre><code class="language-bash">$ SwiftDummyGen input.swift --count 2 --output output.swift
</code></pre>
<h3>🤝 Wrapping Up</h3>
<p>We have successfully built our own <strong>command-line</strong> tool using the <strong>Swift Package Manager</strong>.
Thanks to the <strong>ArgumentParser</strong> framework, handling input arguments becomes straightforward.
Once we compile a release version, the tool is ready to use wherever we need it!</p>
<p>Looking ahead, I plan to go further and support things like:</p>
<ul>
<li>Support for optional and array types (like String? and [Int])</li>
<li>Add more randomization features (such as generating more realistic names)</li>
<li>Add more advanced randomization (e.g. realistic names)</li>
<li>Use all struct types (nested/custom)</li>
</ul>
<p>Hope you liked it 🙂</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CLI</category>
            <category>Swift Package Manager</category>
            <category>Argument Parser</category>
            <enclosure url="https://github.com/henriquestiagoo/ioscoffeebreak-ci/blob/main/issues/57.png?raw=true" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👶 One and a half years of iOS Coffee Break ☕]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue56</link>
            <guid>56</guid>
            <pubDate>Mon, 04 Aug 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I realized the newsletter is already a year and a half old! Still a baby, but definitely but not just born.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #56</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>This week I realized the newsletter is already a <strong>year and a half old</strong>!
Still a baby 👶, but definitely but not just born.</p>
<p>It actually started as a monthly thing, but once I got into the flow of writing and started getting some feedback, it naturally turned into a weekly habit.
Over these past <strong>56 editions</strong>, I've covered all sorts of stuff: WWDC highlights, Apple dev tools, a tiny Swift CLI I made to pick giveaway winners, a SwiftUI navigation setup, and even an <a href="https://apps.apple.com/us/app/coffee-break-news/id6743022409">app</a> I built in the <em>&quot;Building a Newsletter App&quot;</em> series.</p>
<p>Now, after all that writing, I'm taking a short break, just two weeks off while I enjoy some summer time ☀️.</p>
<p>While I'm away, if you've got any ideas, feedback, or just want to say hi, feel free to reach out on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://nowham.dev/posts/github_actions_caching_strategies/">💪 Supercharge Your GitHub Actions with Smart Caching</a></h2>
<p>Did you know you can make your GitHub Actions run faster by <strong>adding caching to your workflows</strong>?</p>
<p>In <a href="https://x.com/No_Wham">Nowham's</a> latest article, you'll learn how to implement efficient caching that can save you hours every week.
Plus, since GHA charges by the minute for private repositories, caching doesn't just save time but it can also reduce your compute costs.</p>
<h2><a href="https://www.artemnovichkov.com/blog/working-with-partially-generated-content-in-xcode-previews">🤖 Working with partially generated content in Xcode previews</a></h2>
<p>One of the highlights of <strong>WWDC 2025</strong> was the introduction of the <strong>Foundation Models</strong> framework.</p>
<p>A particularly useful feature of this framework is guided generation of Swift data structures.
In the latest article by <a href="https://x.com/iosartem">Artem</a>, you'll explore techniques for working with partially generated content in Xcode previews, providing you a practical way to test AI-generated content.</p>
<h2><a href="https://nilcoalescing.com/blog/PresentingLiquidGlassSheetsInSwiftUI/">💧 Presenting Liquid Glass sheets in SwiftUI on iOS 26</a></h2>
<p>This week at work, I've been testing our app with the latest iOS beta to prepare it for <strong>iOS 26</strong>.
One issue I ran into involves partial modals. They don't automatically adopt the new Liquid Glass look or its animations.</p>
<p>Luckily, <a href="https://x.com/NilCoalescing">Natalia's</a> articles showed up just in time.
In them, you'll learn how to take advantage of the new glass-style design for partial sheets in iOS 26, and how to implement smooth, morphing transitions for sheets launched from toolbar buttons using SwiftUI APIs.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/56.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🤝 Why Sticking with Writing actually Matters ✍️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue55</link>
            <guid>55</guid>
            <pubDate>Mon, 28 Jul 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[Writing this newsletter every week has kind of become my happy place! We have crossed 1,000 subscribers, with people finding it through Twitter, LinkedIn, Reddit or my website.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #55</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Writing this newsletter every week has kind of become my happy place!
It is now a regular part of my routine, a way to reflect on recent thoughts and share exciting updates from the community.
It encourages me to keep up with what others are creating and gives me space to unpack my own ideas and thoughts.</p>
<p>I honestly didn't think it would catch on like this. But somehow ... it did.
We have crossed <strong>1,000</strong> subscribers, with people finding it through Twitter, LinkedIn, Reddit or my website.</p>
<p>However, it really made me smile last week when I received direct messages from some of you suggesting topics you'd like to see covered.
That really made my day.
I promise I'll be exploring those ideas in upcoming editions 🤞.</p>
<p>As we reach the <strong>55th</strong> edition of the newsletter, I just want to say thank you 🙏.
Thank you for reading, for engaging, and for being part of this journey.</p>
<p>Have a great week ahead 🤎</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.polpiella.dev/how-i-fix-bugs-in-my-apps">🔎 A Peek into My Debugging Process (With Real Examples)</a></h2>
<p>I'm not sure about you, but I really missed <a href="https://x.com/polpielladev">Pol's</a> writing.</p>
<p>Luckily, he's back! This time, Pol dives into his experiences with <strong>debugging real-world problems in his apps</strong>: from hidden crashes to surprising system prompts, and the tools that help him along the way!</p>
<h2><a href="https://swifttoolkit.dev/posts/lb-digital-rain">⚡ Let's Build: Digital Rain (Matrix Code)</a></h2>
<p>In a previous article of the <a href="https://swifttoolkit.dev/posts/categories/lets-build">Let's Build series</a>, Natan by <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> recreates the iconic Matrix Code effect in the Terminal: Digital Rain.</p>
<p>If you are a fan of <strong>The Matrix</strong>, this is definitely a must-read!</p>
<h2><a href="https://livsycode.com/swiftui/detecting-device-landscape-orientation-in-swiftui/">🚨 Detecting Device Landscape Orientation in SwiftUI</a></h2>
<p>If you have been using SwiftUI, you have likely run into challenges when trying to detect device orientation.</p>
<p>In his latest article, <a href="https://x.com/livsycode">Artem</a> explores a robust method: determining orientation by examining the screen's aspect ratio with <strong>GeometryReader</strong>.</p>
<h2><a href="https://danielsaidi.com/blog/2025/06/19/creating-amazing-loading-animations-with-sf-symbols">⏳ Creating amazing loading animations with SF Symbols</a></h2>
<p>SF Symbols has come a long way since it was first introduced, and starting with <strong>iOS 17</strong>, it now supports advanced styling and dynamic value effects on many of its default icons.</p>
<p>In his latest article, <a href="https://x.com/danielsaidi">Daniel</a> shows how to leverage SF Symbols and their powerful symbol effects to build impressive <strong>loading animations in SwiftUI</strong>, without relying on complex custom code.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/55.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🔎 Identifying Text in an Image Using the Vision framework 👀]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue54</link>
            <guid>54</guid>
            <pubDate>Mon, 21 Jul 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this edition, we'll explore how to use machine learning to detect and locate text within an image by leveraging the Vision framework.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #54</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>3rd and last</strong> edition of the <strong>&quot;Get started with Machine Learning&quot;</strong> series.</p>
<p>In <a href="/issue/issue53">last week's issue</a>, I demonstrated how simple it is to implement text translation using Apple's new <strong>Translation framework</strong>.</p>
<p>This time, we'll explore how to use machine learning to <strong>detect and locate text within an image</strong> by leveraging the <a href="https://developer.apple.com/documentation/vision/">Vision framework</a>.
The <strong>Vision framework</strong> can do much more than find text in an image.
It is also capable of isolating specific areas within images, tracking objects across image sequences, detect hand and body poses and much more!</p>
<blockquote>
<p>If you have worked on projects involving QR code or barcode scanning, chances are you have already made use of the Vision framework, possibly without realizing it.
As for me, my first experience with Vision came when I built a <a href="https://www.tiagohenriques.dev/blog/image-background-remover-cli">Swift command-line tool to remove backgrounds from images ✂️</a>.</p>
</blockquote>
<h3>Creating a Text Recognizer</h3>
<p>Let's begin by exploring how we can use Apple's Vision machine learning framework to extract text from images.</p>
<p>To get started, we'll set up a text recognition component:</p>
<pre><code class="language-swift">import Foundation
import SwiftUI
import Vision

struct TextRecognizer {
    var recognizedText = &quot;&quot;
    var observations: [RecognizedTextObservation] = []

    init(imageResource: ImageResource) async {
        // Create a RecognizeTextRequest.
        var request = RecognizeTextRequest()
        // Set the request's recognitionLevel to .accurate.
        request.recognitionLevel = .accurate
        // Create a UIImage using the ImageResource.
        let image = UIImage(resource: imageResource)
        // Convert the UIImage to Data.
        if let imageData = image.pngData(),
           // The perform request can fail
           // so use try? to proceed only when results are available.
           let results = try? await request.perform(on: imageData) {
            // Store the observations that are returned by the RecognizeTextRequest.
            observations = results
        }

        // Iterate through the observations 
        // and get the top candidate of the potential text values.
        for observation in observations {
            let candidate = observation.topCandidates(1)
            if let observedText = candidate.first?.string {
                recognizedText += &quot;\n\(observedText) &quot;
            }
        }
    }
}
</code></pre>
<p>Here is a quick overview of what the code does:</p>
<ul>
<li>Import the <strong>SwiftUI</strong> and <strong>Vision</strong> frameworks.</li>
<li>Create a <a href="https://developer.apple.com/documentation/vision/recognizetextrequest">RecognizeTextRequest</a>, which is part of the Vision framework's tools for identifying text within images.</li>
<li>Convert the UIImage to Data. This step is required because the <code>RecognizeTextRequest</code> operates on image data, not the Swift image types like UIImage.</li>
<li>Use the <code>perform</code> method on the text request object to analyze the image and gather results. Since this involves async processing, the initializer function must be marked async to properly await the result.</li>
<li>Store the observations that are returned by the <strong>RecognizeTextRequest</strong>.</li>
<li>Iterate through the observations and get the top candidate of the potential text values.</li>
<li>Whenever recognized text is found, we append it to the a local property.</li>
</ul>
<p>Here is how we can integrate it into a SwiftUI view:</p>
<pre><code class="language-swift">import SwiftUI

struct TextRecognitionView: View {
    let imageResource: ImageResource
    @State private var textRecognizer: TextRecognizer?

    var body: some View {
        List {
            Section {
                Image(imageResource)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .clipShape(RoundedRectangle(cornerRadius: 8))
            }
            .listRowBackground(Color.clear)

            Section {
                Text(textRecognizer?.recognizedText ?? &quot;&quot;)
            } header: {
                Text(&quot;Identified text from image&quot;)
            }
        }
        .navigationTitle(&quot;Text Recognition&quot;)
        .task {
            // The initializer is async
            // so you need to call it from an async function or a task.
            textRecognizer = await TextRecognizer(imageResource: imageResource)
        }
    }
}
</code></pre>
<p>And below is a screenshot showing the feature in action:</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue54/text-recognition.webp&quot;
alt=&quot;Text Recognition from Image sample.&quot;
link=&quot;/issues/issue54/text-recognition.webp&quot;
caption=&quot;Text Recognition from Image sample.&quot;
/&gt;</p>
<h3>Highlighting Found Text</h3>
<p>Now that we have identified text in the image, the next step is to visually highlight it by drawing rectangles around the detected text areas.</p>
<p>To do this, we'll start by defining a <code>struct</code> that represents a drawable <a href="https://developer.apple.com/documentation/swiftui/shape">Shape</a>.</p>
<pre><code class="language-swift">import Foundation
import SwiftUI
import Vision

struct BoundsRect: Shape {
    let normalizedRect: NormalizedRect

    func path(in rect: CGRect) -&gt; Path {
        // Convert the normalized coordinates to the coordinates of the image.
        let imageCoordinatesRect = normalizedRect
            .toImageCoordinates(rect.size, origin: .upperLeft)
        return Path(imageCoordinatesRect)
    }
}
</code></pre>
<p>Here is a quick overview of what the code does:</p>
<ul>
<li>Conform to the <strong>Shape</strong> Protocol.</li>
<li>Import the <strong>Vision</strong> framework and define a <code>NormalizedRect</code> property.
Each recognized text observation includes positional data indicating where the text was found within the image.</li>
<li>Convert the normalized coordinates to the coordinates of the image.</li>
</ul>
<p>Then, in our <strong>SwiftUI</strong> view, we can add an overlay to the Image to draw the <code>BoundsRect</code> shapes around each block of identified text.</p>
<p>Here is how we can do it:</p>
<pre><code class="language-swift">struct TextRecognitionView: View {
    [...]
    let boundingColor = Color(red: 0.31, green: 0.11, blue: 0.11)

    var body: some View {
        List {
            Section {
                Image(imageResource)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                    .overlay {
                        if let observations = textRecognizer?.observations {
                            ForEach(observations, id: \.uuid) { observation in
                                // Draw a BoundsRect around 
                                // each text item observed in the image.
                                BoundsRect(normalizedRect: observation.boundingBox)
                                    .stroke(boundingColor, lineWidth: 3)
                            }
                        }
                    }
            }
            [...]
        }
    }
}
</code></pre>
<p>And below is a screenshot showing the text highlighting feature in action:</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue54/text-locations.webp&quot;
alt=&quot;Showing the blocks of text by drawing a rectangle around each location.&quot;
link=&quot;/issues/issue54/text-locations.webp&quot;
caption=&quot;Showing the blocks of text by drawing a rectangle around each location.&quot;
/&gt;</p>
<h2>🤝 Wrapping Up</h2>
<p>The <strong>Vision framework</strong>  is a powerful and versatile tool that can do much more than find text in an image.
It is also capable of isolating specific areas within images, tracking objects across image sequences, detect hand and body poses and much more.</p>
<p>In this chapter, you have learned how to use Vision's built-in features to <strong>detect and locate text in images</strong>.
This serves as a solid starting point for expanding your text recognition capabilities by incorporating more advanced functionalities.</p>
<p>And that wraps up the series <strong>&quot;Get started with Machine Learning&quot;</strong>, with a high-level overview of the ML features and APIs Apple provides.</p>
<p>Hope you liked it 🙂</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Get started with Machine Learning</category>
            <category>Vision Framework</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/54.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[📝 Translating Text into Another Language Using Just a Single Line of Code 😱]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue53</link>
            <guid>53</guid>
            <pubDate>Mon, 14 Jul 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this week's edition, I'll demonstrate how effortlessly we can implement text translation using Apple's new Translation framework.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #53</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>2nd</strong> edition of the <strong>&quot;Get started with Machine Learning&quot;</strong> series.</p>
<p>In the last issue of the newsletter, I introduced a new series titled <a href="/issue/issue52">&quot;Get Started with Machine Learning&quot;</a>, which - no surprises here 🤭 - is all about exploring various machine learning methods.</p>
<p>In this week's edition, I'll demonstrate how effortlessly we can implement text translation using Apple's new <a href="https://developer.apple.com/documentation/translation/">Translation framework</a>.
If we are working with <strong>SwiftUI</strong>, it takes just a <strong>SINGLE</strong> line of code to make it happen.
Sounds too good to be true right? 😱</p>
<p>Read on and see for yourself! 👇</p>
<h3>Translating Text to Another Language</h3>
<p>Let's kick off by exploring how we can use Apple's Translation API.</p>
<p>To start, here is how it works:</p>
<pre><code class="language-swift">import SwiftUI
import Translation

struct TranslationView: View {
    @State private var text = &quot;&quot;
    @State private var showingTranslation = false

    var body: some View {
        NavigationStack {
            List {
                Section {
                    TextField(
                        &quot;Enter the text to translate&quot;, 
                        text: $text, 
                        axis: .vertical
                    )
                }
            }
            .navigationTitle(&quot;Translation Playground&quot;)
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Button(&quot;Translate&quot;) {
                        showingTranslation = true
                    }
                    .disabled(text.isEmpty)
                }
            }
            // the line that makes all possible!
            .translationPresentation(isPresented: $showingTranslation, text: text)
        }
    }
}
</code></pre>
<p>Here is a brief rundown of what the code accomplishes:</p>
<ul>
<li>We import Apple's <strong>Translation</strong> machine learning framework and apply the <code>.translationPresentation</code> view modifier.</li>
<li>This modifier brings up a sheet that displays the original text and its detected language, lets users choose a target language, and shows the translated version of the text.
It also has the ability to read the translated text out loud.
You can either rely on the built-in interface to let the system handle translations for your users, or use the framework to build a more tailored translation experience.</li>
</ul>
<blockquote>
<p>To dive deeper into what the Translation framework can do, explore this <a href="https://developer.apple.com/documentation/translation">guide</a>.</p>
</blockquote>
<p>To try it out, tap the <code>Translate</code> button. Experiment with different languages and use the play icon to listen to how each translation is pronounced.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue53/translation-playground.gif&quot;
alt=&quot;Translation App Playground.&quot;
link=&quot;/issues/issue53/translation-playground.gif&quot;
caption=&quot;Translation App Playground.&quot;
/&gt;</p>
<p><strong>P.S.</strong> Apologies if the Chinese text I pasted isn't quite right! 😅</p>
<h2>🤝 Wrapping Up</h2>
<p>In this edition, we explored how the <strong>Translation framework</strong> leverages machine learning to deliver powerful translation capabilities.
Although it is possible to perform translations without machine learning, this framework streamlines the process, making it both easier and more effective.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Get started with Machine Learning</category>
            <category>Translation Framework</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/53.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🆕 Kicking Off a New Series on Apple's Machine Learning Tools 🤖]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue52</link>
            <guid>52</guid>
            <pubDate>Mon, 07 Jul 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this series, I'll be focusing specifically on the ML aspects of the tutorials, offering a high-level overview of the ML features and APIs Apple provides. Stay tuned!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #52</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><strong>Apple</strong> has recently released a set of new tutorials focused on <a href="https://developer.apple.com/tutorials/develop-in-swift/#new:-natural-language">Machine Learning</a>, and I have been diving into them over the past few days.</p>
<p>As I went through the material, I noticed that a significant portion of my time was actually spent on <strong>SwiftUI</strong>, rather than the core <strong>ML</strong> content 👀 ...</p>
<p>That inspired me to start a new series in the newsletter called <strong>&quot;Get started with Machine Learning&quot;</strong>.
In this series, I'll be focusing specifically on the Machine Learning aspects of the tutorials, offering a <strong>high-level overview of the ML features and APIs Apple provides</strong>.</p>
<blockquote>
<p>Although I'll be covering many of Apple's ML capabilities, I strongly encourage you to go through the official tutorials yourself to get the full experience 👍.</p>
</blockquote>
<h2>Series Plan</h2>
<p>In this series, here is what you can expect to learn:</p>
<ul>
<li>How to use the <a href="https://developer.apple.com/documentation/naturallanguage">Natural Language API</a> to analyze the sentiment in text</li>
<li>How to use the <a href="https://developer.apple.com/documentation/vision">Vision API</a> to identify text within an image</li>
<li>How to train a machine learning model with <a href="https://developer.apple.com/machine-learning/create-ml/">Create ML</a></li>
<li>How to use <a href="https://developer.apple.com/machine-learning/core-ml/">Core ML</a> to integrate new models in your app</li>
<li>How to use the new <a href="https://developer.apple.com/documentation/foundationmodels">Foundation Models</a> framework from iOS 26</li>
</ul>
<h3>Analyzing text</h3>
<p>Let's kick off the series by exploring how to analyze text to identify its sentiment using the <strong>Natural Language API</strong>.</p>
<p>To start, here is how it works:</p>
<pre><code class="language-swift">import NaturalLanguage

class Scorer {
    let tagger = NLTagger(tagSchemes: [.sentimentScore])

    func score(_ text: String) -&gt; Double {
        var sentimentScore = 0.0
        tagger.string = text
        tagger.enumerateTags(
            in: text.startIndex..&lt;text.endIndex,
            unit: .paragraph,
            scheme: .sentimentScore,
            options: []
        ) { sentimentTag, _ in
            if let sentimentString = sentimentTag?.rawValue,
                let score = Double(sentimentString) {
                sentimentScore = score
                return true
            }
            return false
        }
        return sentimentScore
    }
}
</code></pre>
<p>The <a href="https://developer.apple.com/documentation/naturallanguage/nltagger">NLTagger</a> class allows you to specify a tagging scheme that extracts various types of information from text - such as its grammatical role or the language it is written in.
Among the available schemes, we are focusing on <code>.sentimentScore</code> for this example.
This particular scheme provides a sentiment value ranging from <code>1.0</code> (the most positive 😃) to <code>-1.0</code> (the most negative 😢).</p>
<p>Here is an example of how to implement it:</p>
<pre><code class="language-swift">let text = &quot;I enjoy hard hikes. When my heart is pumping and I'm being challenged, I feel great.&quot;

let scorer = Scorer()
let score = scorer.score(text)
</code></pre>
<p>In this sample, the <code>score</code> property gets a value of <code>1.0</code>, indicating extremely positive sentiment. Great! 💪</p>
<p>Feel free to experiment on your own by entering various types of text to see how the API reacts!</p>
<h2>🤝 Wrapping Up</h2>
<p><strong>Machine learning</strong> can work across different input and output types.
In this edition, we explored Apple's <strong>Natural Language</strong> framework along with sentiment analysis, demonstrating how we can input text and obtain a numerical sentiment score in return.</p>
<p>As a next step, we can enhance our approach by modeling sentiment characteristics, for example, defining an enum to ensure consistent representation of sentiment values throughout the app.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Get started with Machine Learning</category>
            <category>Natural Language</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/52.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✍️ Keeping My README Up-to-Date with a Swift CLI Tool and GitHub Actions 👌]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue51</link>
            <guid>51</guid>
            <pubDate>Mon, 30 Jun 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I set up an automated workflow that updates the README file in my newsletter repository every week. Here is what I have learned from it!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #51</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Running a newsletter is not an easy task 🥵!
It takes a lot of time and effort, especially when you are juggling a full-time job.
I am always on the lookout for ways to streamline my workflow, aiming to automate repetitive tasks that usually require my direct involvement.</p>
<p>One such task is <strong>keeping my newsletter repository current</strong> and ensuring that <strong>all references to it remain aligned</strong>.
Recently, I set up an <strong>automated workflow that updates the README file in my newsletter repository every week</strong>.
This is done using a <strong>Swift-based command-line tool</strong> and <strong>GitHub Actions</strong>.</p>
<p>This week, I would like to walk you through that process and what I learned from it! 👇</p>
<h2>The Plan</h2>
<p>In this edition, my plan was to create a <strong>command-line tool that fetches the latest issues in my newsletter</strong> and <strong>updates the README.md</strong> file with that content.
To make it fully automated, I also created a <strong>GitHub workflow that runs this tool on a regular schedule</strong>. Here is the high-level plan:</p>
<ul>
<li>Develop a Swift command-line that:
<ul>
<li>Collects the most recent newsletter issues.</li>
<li>Updates a specified file (provided via the ArgumentParser) with the new data.</li>
</ul>
</li>
<li>Set up a GitHub Actions workflow that:
<ul>
<li>Executes once per week.</li>
<li>Runs the CLI tool to fetch and insert the latest content.</li>
<li>Commits and pushes any updates to the repository if there are changes.</li>
</ul>
</li>
</ul>
<h3>Building the Executable</h3>
<p>The first step involves creating a Swift command-line executable.</p>
<blockquote>
<p>I won't go into the details of how to build a Swift CLI here, but if you are curious, feel free to take a look at this <a href="https://www.swift.org/getting-started/cli-swiftpm/">guide</a>.</p>
</blockquote>
<pre><code class="language-swift">import ArgumentParser
import Foundation

@main
struct feedparser: AsyncParsableCommand {
    @Argument(help: &quot;The path of the destination README file.&quot;)
    var destination: String

    func run() async throws {
        let apiClient = APIClient()

        do {
            // fetch issues from the newsletter API
            let issues = try await apiClient.getIssues()
            let latestIssues = (issues.count &lt; 10) ? issues : Array(issues.prefix(10))
            // generate content from latest issues
            let content = MarkdownGen.makeContent(from: latestIssues)
            // write to the README.md file
            try content.write(to: URL(fileURLWithPath: destination), atomically: true, encoding: .utf8)
            print(&quot;✅ Successfully written to \(destination) file.&quot;)
        } catch let error {
            print(&quot;❌ Error: \(error)&quot;)
        }
    }
}
</code></pre>
<p>Here is a quick overview of what the following code does:</p>
<ul>
<li>The <code>APIClient</code> is responsible for retrieving newsletter issues, making use of Swift's <strong>async/await</strong> concurrency model.</li>
<li>Then, <code>MarkdownGen.makeContent()</code> is called to generate the markdown-formatted string that will be written to a file.</li>
<li>Finally, this content is written to a file - <code>README.md</code> in my case.</li>
</ul>
<h3>Setting Up the GitHub Workflow</h3>
<p>Next, I needed to create the automation using GitHub Actions:</p>
<pre><code class="language-bash">name: Fetch latest newsletter issues and update the README.md

on:
  push:
  schedule:
    - cron: &quot;0 0 * * 2&quot; # At 00:00 every Tuesday.

jobs:
  build:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v4
      - run:  swift run feedparser README.md
      - run: |
          git config user.name henriquestiagoo
          git config user.email henriquestiago@ua.pt
          git add README.md
          git commit -m &quot;[generated by github action workflow]: Update latest newsletter issues in `README.md` file&quot; || echo &quot;No changes to commit&quot;
          git push origin main || echo &quot;No changes to commit&quot;
</code></pre>
<p>Here is a summary of the workflow setup:</p>
<ul>
<li>I configured the workflow to trigger both on every push and once weekly using the push and schedule triggers.</li>
<li>The checkout action ensures the latest version of the code is pulled from the repository.</li>
<li>After that, the CLI tool is executed to fetch the latest issues and update the <code>README.md</code> file.</li>
<li>If there are any changes, the workflow commits those updates back to the repository.</li>
</ul>
<p>Here is what the generated <code>README.md</code> looks like after the workflow has been executed:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue51/readme-output.webp&quot;
alt=&quot;The output of my README file.&quot;
link=&quot;/issues/issue51/readme-output.webp&quot;
caption=&quot;The output of my README file.&quot;
/&gt;</p>
<h3>Configuring Cirrus Runners</h3>
<p>As a token of appreciation to <a href="https://cirruslabs.org/">Cirrus Labs</a> for sponsoring this edition, I would like to demonstrate how you can run this workflow using the <a href="https://cirrus-runners.app/">Cirrus Runners</a> infrastructure.
All it takes is updating the <code>runs-on:</code> property by replacing the GitHub runner with the appropriate Cirrus runner image.</p>
<pre><code class="language-bash">name: Fetch latest newsletter issues and update the README.md

[...]

jobs:
  build:
    name: &quot;Run on the fastest infrastructure!&quot;
    #runs-on: macos-latest
    runs-on: ghcr.io/cirruslabs/macos-runner:sequoia

    [...]
</code></pre>
<blockquote>
<p>To get started with Cirrus Runners, you need to install the Cirrus Runners GitHub App in your GitHub organization. For detailed instructions, refer to the Cirrus Runners <a href="https://cirrus-runners.app/setup/">setup guide</a>.</p>
</blockquote>
<p>And that's everything you need to do to move over to Cirrus Runners' infrastructure!</p>
<h2>🤝 Wrapping Up</h2>
<p><strong>Swift CLI tools</strong> paired with <strong>GitHub Actions</strong> make for a powerful automation setup, ideal for handling repetitive or manual tasks.
In this case, I have combined them to ensure my newsletter's <code>README</code> file is always up-to-date with the content on the website - all of this without needing input from my side.</p>
<p>The project is fully open-source, so if you are interested, feel free to check out the <a href="https://github.com/henriquestiagoo/ioscoffeebreak-ci">repository</a>.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CLI</category>
            <category>CI/CD</category>
            <category>GitHub Actions</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/51.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[⬆️ Top WWDC Reads from the iOS Community 📖]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue50</link>
            <guid>50</guid>
            <pubDate>Mon, 23 Jun 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[If you are reading this, good news — I have handpicked several standout articles that are definitely worth your time. You will find them in this week's edition.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #50</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.
Can you believe this is already the <strong>50th</strong> edition of the newsletter? 🤗</p>
<p>To mark this milestone — which might seem small, but feels huge — I took a little break to explore the stunning island of São Miguel in the Açores 🏝️.
Just kidding, the trip had been in the works for months!</p>
<p>It turned out to be a week packed with adventure: hiking trails, soaking in hot springs, and taking in some truly unforgettable scenery.</p>
<p>If you are a developer, here is your friendly reminder to step away from the screen every now and then.
Take time off, unplug completely — your future self (and possibly your partner) will thank you for it.</p>
<p>That said, if you absolutely must get some tasks done, look into ways to automate them.
For instance, last week's newsletter was fully prepped in advance: from going live to email sends and social media posts.
I use <a href="https://resend.com/">Resend</a> as my email provider, and their latest tools make scheduling a breeze.</p>
<p>Now that I am back, I have been catching up on what other devs are building with the new features and updates from WWDC 2025.
If you are reading this, good news — I have handpicked several standout articles that are definitely worth your time.
You will find them in this week's edition.</p>
<p>Happy reading!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://livsycode.com/swiftui/using-the-foundation-models-framework-for-on-device-ai-in-swiftui/">🤖 Using the Foundation Models Framework for On-Device AI in SwiftUI</a></h2>
<p>One of the features announced at <strong>WWDC 2025</strong> that excited me the most was the <a href="https://developer.apple.com/documentation/foundationmodels">Foundation Models</a> framework, and <a href="https://x.com/livsycode">Artem</a> didn't just write one — but two insightful pieces diving into it.
I couldn't choose between them, so I decided to feature both!</p>
<p>In this article, <strong>Artem</strong> demonstrates how to ask a question and get a live, streaming reply using this on-device AI model.
The framework gives developers the tools to bring on-device AI functionality into their SwiftUI apps, including real-time text generation with very little setup required — I can already spot countless use cases that could benefit from this kind of smart functionality.</p>
<h2><a href="https://livsycode.com/swiftui/exploring-the-generable-and-guide-macros-in-foundationmodels/">🤠 Exploring the @Generable and @Guide Macros in FoundationModels</a></h2>
<p><a href="https://x.com/livsycode">Artem's</a> second article takes a closer look at the new <code>@Generable</code> and <code>@Guide</code> macros introduced in the <strong>Foundation Models</strong> framework.
These macros simplify the process of generating structured data for particular model types by leveraging language models.</p>
<h2><a href="https://useyourloaf.com/blog/wwdc-2025-viewing-guide/">📋 WWDC 2025 Viewing Guide</a></h2>
<p>In my opinion, <a href="https://x.com/kharrison">Keith Harrison</a> put together the most comprehensive <strong>WWDC 2025 viewing guide</strong> to help you organize and prioritize the sessions you want to catch.</p>
<p>If you happened to miss the Apple Platforms State of the Union or any of the sessions — or if you are simply looking for a solid recap of last week's announcements — this article is definitely worth a read!</p>
<h2><a href="https://danielsaidi.com/blog/2025/06/10/webview-is-finally-coming-to-swiftui">🧑‍💻 WebView is Finally Coming to SwiftUI</a></h2>
<p>Before the release of iOS, macOS, and visionOS 26, displaying web content directly within a SwiftUI app was not straightforward.
Since SwiftUI didn't have a built-in WebView, we had to rely on WKWebView from UIKit or AppKit, bridging it into SwiftUI using UIViewRepresentable or NSViewRepresentable.
Another option was to use third-party libraries like <a href="https://github.com/danielsaidi/WebViewKit">WebViewKit</a>, a tool developed by <a href="https://x.com/danielsaidi">Daniel</a> a few years back.</p>
<p>But at WWDC 2025, <strong>Apple finally introduced a native WebView component for SwiftUI</strong> — along with other web-focused enhancements.
In this article, <strong>Daniel</strong> takes a deep dive into the new WebView, showcasing how it works and providing practical code examples to help you take full advantage of this long-awaited addition.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>WWDC</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/50.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🫣 Am I too late to share my thoughts on WWDC 2025? 👨‍💻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue49</link>
            <guid>49</guid>
            <pubDate>Mon, 16 Jun 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[The most exciting week of the year for iOS developers has officially wrapped up and I have decided to put together some thoughts on the frameworks and features that stood out to me.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #49</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><strong>The most exciting week of the year for iOS developers</strong> has officially wrapped up! 🥹
Between watching sessions and diving into technical write-ups, there is no shortage of opportunities to learn, experiment and get inspired!</p>
<p>Luckily, my team lead joined the fun and organized a full day dedicated to watching selected sessions together and sharing our takeaways.
Naturally, we made sure to stock up on snacks and drinks to keep things more interesting!</p>
<p>&lt;StaticImage
src=&quot;/issues/issue49/team-wwdc-activity.webp&quot;
alt=&quot;Doing my best not to eat all the snacks within the first half hour.&quot;
link=&quot;/issues/issue49/team-wwdc-activity.webp&quot;
caption=&quot;Doing my best not to eat all the snacks within the first half hour.&quot;
/&gt;</p>
<p>The day turned out to be incredibly valuable — we covered nine sessions in total and had some great discussions about how to approach our upcoming sprints.</p>
<p>Below, I have put together some thoughts on the frameworks and features that stood out to me:</p>
<h3>Liquid Glass</h3>
<p><strong>Liquid Glass</strong> is a significant new step and evolution of the look and feel of Apple Software.
It introduces a flexible, dynamic layer to apps and system experiences across Apple's ecosystem of products.</p>
<p>It merges different visual and interface elements throught Apple's software design history:</p>
<ul>
<li>Aqua's tridimensional surfaces</li>
<li>iOS 7's visual layers</li>
<li>iPhone X's fluidity of gestures</li>
<li>Dynamic Island's motion dynamics and merge behaviors.</li>
</ul>
<p>From what I have seen, this design has received widespread criticism on social media — primarily for accessibility concerns such as poor contrast, visually overwhelming backgrounds and distracting animations.</p>
<p>That said, this is still a beta release, and I am confident Apple will refine and resolve these issues in the final version.</p>
<h3>Foundation Models Framework</h3>
<p>It is no surprise Apple delivered on-device model APIs, but the usability of the Foundation Models API genuinely impressed me!
This new framework allows you to interact with an on-device Large Language Model (LLM) designed for everyday use cases.
It is great for things like summarization, extraction, classification and more.</p>
<p>Using the model is incredibly straightforward — it takes just three lines of code.
Here is one example shared in one of Apple's sessions:</p>
<pre><code class="language-swift">import FoundationModels
  
// start a language model session.
let session = LanguageModelSession()

// provide a prompt.
let prompt = &quot;Generate a bedtime story about a fox.&quot;
let response = try await session.respond(to: prompt)

print(response.content)
</code></pre>
<p>On top of that, the <code>@Generable</code> macro makes defining structured outputs much easier, removing the usual pain of parsing model responses and streamlining the development process.</p>
<blockquote>
<p>For more on how guided generation works, check out <a href="https://developer.apple.com/videos/play/wwdc2025/286/">Meet Foundation Models framework</a> talk.</p>
</blockquote>
<p>I am genuinely excited to spend more time exploring this new framework.
While I expect there will be some constraints given the size of the on-device LLM, the benefits of local execution and the wide spread of use cases make it especially attractive from a developer's perspective.</p>
<h3>SwiftUI</h3>
<p>SwiftUI has seen significant upgrades across multiple core areas this year, such as <strong>list, scrolling behavior, performance profiling and debugging tools</strong>.
The framework has also broadened what views can do — from <strong>rich text editing</strong> to <strong>3D chart rendering</strong>, there are several exciting new view types and updates to existing ones.</p>
<p>One particularly welcome change is the ability to embed web content directly within SwiftUI apps.
Apple has introduced a complete set of SwiftUI APIs for <strong>WebKit</strong>, including <strong>support for WebView</strong>.</p>
<p>Here is an example Apple highlighted during one of their sessions:</p>
<pre><code class="language-swift">struct HikeGuideWebView: View {
	var body: some View {
		WebView(url: sunshineMountainURL)
	}
}
</code></pre>
<blockquote>
<p>To learn more about all these new WebKit APIs, check session <a href="https://developer.apple.com/videos/play/wwdc2025/231/">Meet WebKit for SwiftUI</a>.</p>
</blockquote>
<h3>UIKit</h3>
<p>In my opinion, the major enhancement is the built-in support for Swift <strong>Observable</strong> objects in UIKit.
UIKit now integrates <strong>Swift Observation</strong> at its foundation: in update methods like <code>layoutSubviews</code>, it automatically tracks any <strong>Observable</strong> you reference, wires up dependencies, and invalidates the right views, without requiring you to manually call <code>setNeedsLayout</code>.</p>
<p>Here is a demonstration of automatic observation tracking in action:</p>
<pre><code class="language-swift">// Using an Observable object and automatic observation tracking
@Observable class UnreadMessagesModel {
    var showStatus: Bool
    var statusText: String
}

class MessageListViewController: UIViewController {
    var unreadMessagesModel: UnreadMessagesModel
    var statusLabel: UILabel
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        statusLabel.alpha = unreadMessagesModel.showStatus ? 1.0 : 0.0
        statusLabel.text = unreadMessagesModel.statusText
    }
}
</code></pre>
<h3>Swift</h3>
<p>Swift improvements span various parts of the development workflow — from writing code to building and debugging.</p>
<p>A key factor in developer productivity is how fast and efficient the tools are.
<strong>Swift 6.2</strong> delivers notable performance gains, especially for projects that make use of macro-based APIs.
In many cases, <strong>clean build times have been dramatically reduced</strong> — in some projects, by several minutes.</p>
<h3>Xcode</h3>
<p>This year, Apple is launching a new feature called <strong>Playground</strong>, designed to help you experiment with code more efficiently.</p>
<p>Much like previews, we can embed a playground directly within your document, and the output from running your code will be displayed in a dedicated canvas tab.</p>
<p>Personally, I find this tool incredibly handy — I often need to step away from full Xcode projects just to try out a snippet of code.
It also offers a more straightforward approach to testing code and can help spark ideas for writing better unit tests.
Here is an example:</p>
<pre><code class="language-swift">import Playgrounds

#Playground {
    let landmark = Landmark.exampleData.first
}
</code></pre>
<h2>🤝 Wrapping Up</h2>
<p>Several other exciting features were announced as well, and I am eager to explore them in more depth over the coming week.
I have bookmarked quite a few sessions that I haven't had a chance to watch yet 😅.</p>
<p>Over the next few months, I plan to dive into the new APIs and share a more in-depth look at what they offer.</p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>WWDC</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/49.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨‍🚀 Launching the App to the App Store 🚀]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue48</link>
            <guid>48</guid>
            <pubDate>Mon, 09 Jun 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[It is time to bring the app to life! The next steps involve preparing it for the App Store and launching it to all users. Let's get to it!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #48</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>11th</strong> edition of the <strong>&quot;Building a Newsletter App&quot;</strong> series.</p>
<p>Last week, I guided you through <a href="/issue/issue47">designing a simple app icon</a> — starting with a placeholder, creating an initial version and refining it until it felt just right!</p>
<p>Now, after <strong>11</strong> issues in this series, it is time to bring the app to life!
The next steps involve <strong>archiving the app</strong>, <strong>preparing it for the App Store</strong> and finally <strong>launching it</strong> to all users.</p>
<blockquote>
<p>It has been a while since I last published <a href="https://apps.apple.com/us/app/padel-time/id6471981060">Padel Time</a>, so I revisited my own <a href="https://www.ioscoffeebreak.com/issue/issue14">guide</a> on the process — I recommend checking it out to follow along more easily!</p>
</blockquote>
<h2>The Plan</h2>
<p>To distribute my <strong>Coffee Break News</strong> app for beta testing or public release on the App Store, I followed these steps:</p>
<ul>
<li>Set up a distribution provisioning profile and certificate.</li>
<li>Create an App Store Connect record for the app.</li>
<li>Archive and upload the app using Xcode.</li>
<li>Configure the app's metadata and details in App Store Connect.</li>
<li>Submit the app for review.</li>
</ul>
<h3>Configuring an iOS Distribution Profile and Certificate</h3>
<p>To set this up, I accessed my <a href="https://developer.apple.com/">Apple Developer</a> account and went to <code>&quot;Certificates, Identifiers &amp; Profiles&quot;</code>.
I generated an <strong>App Store Distribution Certificate</strong>, installed it in my Mac's Keychain, then created and downloaded a matching <strong>Distribution Provisioning Profile</strong>.
After that, I integrated both into Xcode for proper code signing.</p>
<p>Here is how my <code>&quot;Signing &amp; Capabilities&quot;</code> settings look in Xcode:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue48/provision_profiles.webp&quot;
alt=&quot;Choosing the iOS provision profile for production.&quot;
link=&quot;/issues/issue48/provision_profiles.webp&quot;
caption=&quot;Choosing the iOS provision profile for production.&quot;
/&gt;</p>
<h3>Setting Up an App Store Connect Entry</h3>
<p>To register the app, I logged into <strong>App Store Connect</strong>, navigated to <code>&quot;My Apps&quot;</code>, and selected <code>&quot;New App&quot;</code>.
I then filled in essential details like the <strong>app name</strong>, <strong>primary language</strong>, <strong>bundle ID</strong>, and <strong>SKU</strong>.</p>
<p>Here is my App Store Connect entry:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue48/new_app_record_app_store_connect.webp&quot;
alt=&quot;Creating an app record in App Store Connect.&quot;
link=&quot;/issues/issue48/new_app_record_app_store_connect.webp&quot;
caption=&quot;Creating an app record in App Store Connect.&quot;
/&gt;</p>
<h3>Archiving and Uploading the app with Xcode</h3>
<p>To package and submit the app using Xcode, I followed these steps:</p>
<ul>
<li>Opened <code>&quot;Product&quot;</code> &gt; <code>&quot;Archive&quot;</code> to generate an archive.</li>
<li>Selected the archive and clicked <code>&quot;Distribute App&quot;</code>, choosing <code>&quot;App Store Connect&quot;</code>.</li>
<li>Completed the validation, code signing, and upload process.</li>
</ul>
<p>Here is my archive, prepped for distribution:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue48/archive_xcode.webp&quot;
alt=&quot;Archiving the app in Xcode.&quot;
link=&quot;/issues/issue48/archive_xcode.webp&quot;
caption=&quot;Archiving the app in Xcode.&quot;
/&gt;</p>
<h3>Configuring App Metadata in App Store Connect</h3>
<p>In App Store Connect, under the <code>&quot;App Store&quot;</code> tab, I needed to enter key details in the <code>&quot;App Information&quot;</code> section, such as supported languages, categories, and my app's privacy policy URL.
Next, I uploaded screenshots and added important metadata, including the app description, keywords, support URL, and marketing URL.</p>
<p>Here are my app previews and screenshots that will be displayed on the App Store:</p>
<p>&lt;Images3Grid
src=&quot;/issues/issue48/app_store_1.webp&quot;
alt=&quot;App Store screenshot 1.&quot;
link=&quot;/issues/issue48/app_store_1.webp&quot;
caption=&quot;App Store screenshot 1.&quot;
src2=&quot;/issues/issue48/app_store_2.webp&quot;
alt2=&quot;App Store screenshot 2.&quot;
link2=&quot;/issues/issue48/app_store_2.webp&quot;
caption2=&quot;App Store screenshot 2.&quot;
src3=&quot;/issues/issue48/app_store_3.webp&quot;
alt3=&quot;App Store screenshot 3.&quot;
link3=&quot;/issues/issue48/app_store_3.webp&quot;
caption3=&quot;App Store screenshot 3.&quot;
/&gt;</p>
<blockquote>
<p>I use <a href="https://apps.apple.com/us/app/framous-screenshot-frames/id6636520519">Framous</a> from <a href="https://x.com/_chuckyc">Charlie Chapman</a> to add device frames to my screenshots — highly recommended for quick, polished results!</p>
</blockquote>
<h3>Submitting the App for Review</h3>
<p>To submit my app for review, I navigated to the <code>&quot;Build&quot;</code> section in App Store Connect and selected <code>&quot;Select a build before you submit your app&quot;</code>.
After picking the uploaded build from Xcode, I clicked <code>Done</code>, then <code>Save</code>, and finally <code>Submit for Review</code>.
After that, <strong>Apple</strong> reviewed and approved the app!</p>
<h2>🤝 Wrapping Up</h2>
<p>I am thrilled to announce it is now live — go check it out and let me know your thoughts!
What are you waiting for? <a href="https://apps.apple.com/app/ios-coffee-break/id6743022409">Get the App now! 🚀</a></p>
<p>Have any feedback, suggestions, or ideas to share?
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>.</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://nowham.dev/posts/ios_terminal_productivity/">📖 Terminal Setup &amp; Scripts</a></h2>
<p>Recently, <a href="https://x.com/No_Wham">Noam</a> had to configure a new machine, which led him to revisit his terminal setup.
Fortunately for us, he took the time to document his own terminal configuration — <strong>including the aliases, commands</strong> and theme he relies on daily.</p>
<p>You can start with the simple aliases and essential functions, and slowly expand your setup from there.
Your future self will appreciate it!</p>
<h2><a href="https://github.com/horseshoe7/SwiftUI-MVVM-C">🔀 Navigation Coordination in SwiftUI</a></h2>
<p>A while back, I published a <a href="https://www.tiagohenriques.dev/blog/swiftui-refactor-navigation-layer-using-coordinator-pattern">blog post</a> about SwiftUI navigation, where I refactored an older navigation layer to adopt the Coordinator Pattern.
Not long after that, <a href="https://www.linkedin.com/in/soconnor79">Stephen</a> came across my post, reached out for a quick chat and decided to spin up a sandbox project to explore the idea further.</p>
<p>My original implementation had a few limitations — for instance, it didn't allow child coordinators to manage the parent's navigation path and the navigation logic wasn't fully decoupled from the views, among other things.
Stephen took the concept, enhanced it significantly, and this week, he open-sourced his new version - <a href="https://github.com/horseshoe7/SwiftUI-MVVM-C">NavigationCoordination in SwiftUI</a>.</p>
<p>This kind of collab highlights one of the great advantages of sharing your work publicly: <strong>with a bit of luck, you can spark ✨ interest in other devs, who may even build upon and improve your ideas!</strong> In case of doubt, do it! 💪</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>App Store</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/48.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨‍🎨 Creating an App Icon with Zero Design Skills 🎨]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue47</link>
            <guid>47</guid>
            <pubDate>Mon, 02 Jun 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I will walk you through designing a simple app icon — even if you have zero design experience like me!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #47</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>10th</strong> edition of the <strong>&quot;Building a Newsletter App&quot;</strong> series.</p>
<p>Last week, I walked you through the process of <a href="/issue/issue46">localizing my newsletter app using a String Catalog</a>, enabling support for two languages: English and Portuguese.</p>
<p>As the app evolves, one thing that keeps catching my eye is the blank placeholder icon.
Hiring a designer is always an option, but if you are on a budget or just enjoy learning, why not try creating one yourself? 😉</p>
<p>This week, I will walk you through <strong>designing a simple app icon</strong> — even if you have <strong>zero design experience</strong> like me!</p>
<h2>The Plan</h2>
<p>As developers, designing app icons should be on the bottom of our priorities.
Yet, here we are, so here is the plan for crafting a version of our app icon:</p>
<ul>
<li>Creating a placeholder App Icon</li>
<li>Understand the key principles for designing better app icons</li>
<li>Creating the first version of your app icon</li>
<li>Tweaking the design until it feels right</li>
</ul>
<h3>Creating a Placeholder App Icon</h3>
<p>As I mentioned earlier, the default blank placeholder icon bothers me.
But it doesn't have to stay that way!
With <strong>AI</strong> tools, you can generate a simple app icon by providing a prompt.</p>
<p>Personally, I like using <a href="https://apps.apple.com/us/app/bakery-simple-icon-creator/id1575220747">Bakery</a>, a <strong>macOS</strong> app by <a href="https://x.com/jordibruin">Jordi Bruin</a>, to quickly create a placeholder icon.
Just pick a <strong>background color</strong> and a <strong>symbol or emoji</strong> and the app generates a preview.
If you are happy with it, simply <strong>drag and drop</strong> it into <strong>Xcode</strong>.</p>
<p>Here is the placeholder version of my app icon.</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue47/placeholder_app_icon.webp&quot;
alt=&quot;Using the Bakery App to get an app icon placeholder.&quot;
link=&quot;/issues/issue47/placeholder_app_icon.webp&quot;
caption=&quot;Using the Bakery App to get an app icon placeholder.&quot;
/&gt;</p>
<p>Not bad right? Yet, I believe I can do better!</p>
<h3>Understand the Key Principles for Designing Better App Icons</h3>
<p>I am no design expert, but I have learned some essential principles from <a href="https://x.com/flora_dam">Flora Damiano</a>, who gave a great <a href="https://www.youtube.com/watch?v=6s_GkICOvYw">talk</a> at <strong>Swift Leeds 2024</strong> on crafting app icons.</p>
<p>Here are the key aspects to focus on. Make your app icon:</p>
<ul>
<li><strong>Versatile:</strong> Keep you icon legible at every size on every device you are developing for</li>
<li><strong>Consistent:</strong> Your icon should resemble your App's identity</li>
<li><strong>Original:</strong> Use color and shape to convey your App's soul in a unique way</li>
<li><strong>Memorable:</strong> Create an emotional connection with the user of your App</li>
</ul>
<h3>Creating the First Version of Your App Icon</h3>
<p>I use <a href="https://www.sketch.com/">Sketch</a> to prototype my app icons, but you can achieve similar results with any design tool of your choice.
If you are new to Sketch, I recommend checking out their <a href="https://www.sketch.com/guides/">guides and courses</a> to learn the basics.</p>
<blockquote>
<p>Your icon should be designed at the proper resolution to be implemented in Xcode. In iOS and macOS, for example, the icon has to be sized at <code>1024x1024px</code>.</p>
</blockquote>
<p>Once the icon is designed, it needs to be exported in multiple sizes and resolutions.
Thankfully, <strong>Apple's Design Resources</strong> provide free Sketch and Photoshop templates.
Simply insert your icon, and the tool will generate all necessary assets for <strong>Xcode</strong>.</p>
<blockquote>
<p>You can grab the app icon Sketch template from <a href="https://developer.apple.com/design/resources/">Apple's Design Resources</a>. In this <a href="https://medium.com/kennethlng/how-to-use-apples-app-icon-sketch-template-for-xcode-2a4458c75ac1">guide</a>, you can see how to open the template in Sketch.</p>
</blockquote>
<h4>iOS Coffee Break Newsletter Sticker</h4>
<p>At <strong>Swift Leeds 2024</strong>, I ran a marketing campaign for the newsletter by sharing stickers with fellow developers.
That gave me a solid starting point for my app icon design. Here is the initial version:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue47/ioscoffeebreak_starter.webp&quot;
alt=&quot;iOS Coffee Break App starter app icon&quot;
link=&quot;/issues/issue47/ioscoffeebreak_starter.webp&quot;
caption=&quot;iOS Coffee Break App starter app icon.&quot;
/&gt;</p>
<p>While I like how the icon looks, there is a major issue — the lettering isn't readable on a iPhone/iPad screen.
Unfortunately, that means this version won't work!</p>
<h3>Tweaking the design until it feels right!</h3>
<p>After creating the first version of my icon, I realized the lettering had to go — it just wasn't working.
Additionally, the background color needed more contrast with the coffee cup to improve visibility.
So, I explored with different color variations and adjustments until I landed on a final version that I was happy with! 🙂</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue47/ioscoffeebreak_final.webp&quot;
alt=&quot;iOS Coffee Break App final app icon&quot;
link=&quot;/issues/issue47/ioscoffeebreak_final.webp&quot;
caption=&quot;iOS Coffee Break App final app icon.&quot;
/&gt;</p>
<h3>🤝 Wrapping Up</h3>
<p>I can't way to share the app with you! I am almost there, I promise!
But before that, I need to set up everything in the <strong>App Store</strong> to make it available for users.</p>
<p>In the next couple of weeks, I plan to walk you through the process of publishing an app to the <strong>App Store</strong>.
Stay tuned!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Designing App Icons</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/47.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[📋 Localizing An App with a String Catalog 🌎]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue46</link>
            <guid>46</guid>
            <pubDate>Mon, 26 May 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I will guide you through localizing the newsletter app using a String Catalog! Let's explore how to use this powerful new tool to make your app speak different languages!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #46</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>9th</strong> edition of the <strong>&quot;Building a Newsletter App&quot;</strong> series.</p>
<p>Last week, I showed you how to <a href="/issue/issue45">handle deep links</a> from notifications in my newsletter app, ensuring users land on the issue detail page when tapping push notifications of a certain type.</p>
<p>This week, I will guide you through <strong>localizing the newsletter app using a String Catalog</strong>!
Localization is key to making your app accessible to a global audience.</p>
<p><strong>Before Xcode 15</strong>, managing translations with multiple <code>.strings</code> and <code>.stringsdict</code> files was tedious and error-prone.
Mistakes could easily break your build.
Now, <strong>with Xcode 15 or higher</strong>, <strong>Apple</strong> has introduced <a href="https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog">String Catalogs</a>, a streamlined and user-friendly way to handle localization efficiently.
Let's explore how to use this powerful new tool to make your app speak different languages!</p>
<h2>The Plan</h2>
<p>The goal is to localize the app into <strong>English</strong> and <strong>Portuguese</strong>, but the process applies to any language.
Here is the plan:</p>
<ul>
<li>Add a String Catalog to the project</li>
<li>Include new languages in the project settings</li>
<li>Add localizable text to the catalog</li>
<li>Handle pluralization for different cases</li>
</ul>
<h3>Adding a String Catalog to the Project</h3>
<p>To add a string catalog to your project, go to <code>File</code> &gt; <code>New</code> &gt; <code>File from Template</code>. In the pop-up window, select your platform, type &quot;string catalog&quot; in the search bar, choose String Catalog, and click <code>Next</code>.
You can keep the default name as <strong>Localizable</strong>. Pick a save location, and click <code>Create</code> to finalize.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue46/add_string_catalog.webp&quot;
alt=&quot;Adding a string catalog to the project.&quot;
link=&quot;/issues/issue46/add_string_catalog.webp&quot;
caption=&quot;Adding a string catalog to the project.&quot;
/&gt;</p>
<h3>Adding a Language to your Project</h3>
<p>To make the app support multiple languages, you need to add additional languages to your project.
Select the <strong>string catalog</strong> in the <strong>Project Navigator</strong>, then click the <code>(+)</code> button at the bottom of the <strong>string catalog editor</strong> and choose the language you want to include.
In my case, I am adding <strong>Portuguese</strong> as the additional language.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue46/add_language.webp&quot;
alt=&quot;Adding a language to the project.&quot;
link=&quot;/issues/issue46/add_language.webp&quot;
caption=&quot;Adding a language to the project.&quot;
/&gt;</p>
<h3>Adding the Localizable text to the String Catalog</h3>
<p><strong>Xcode</strong> keeps your <strong>string catalog</strong> updated with your app's localizable content each time you build the project.
To populate it, go to <code>Product &gt; Build</code>, and <strong>Xcode</strong> will automatically detect and add localizable strings.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue46/adding_translations.webp&quot;
alt=&quot;Adding localizable text to the string catalog.&quot;
link=&quot;/issues/issue46/adding_translations.webp&quot;
caption=&quot;Adding localizable text to the string catalog.&quot;
/&gt;</p>
<blockquote>
<p>You can monitor the translation progress for each language by checking the indicator next to its name in the String Catalog.</p>
</blockquote>
<h3>Adding Pluralizations</h3>
<p>String catalog simplifies the localization of word variations.
Pluralization is now easier than ever - just right, click a row and select <code>&quot;Vary by Plural&quot;</code>, which adds <code>One</code> and <code>Other</code> options.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue46/vary_plural.webp&quot;
alt=&quot;Varying a string by plural.&quot;
link=&quot;/issues/issue46/vary_plural.webp&quot;
caption=&quot;Varying a string by plural.&quot;
/&gt;</p>
<blockquote>
<p>You can also vary text based on the device type, which is especially useful when supporting multiple platforms.</p>
</blockquote>
<h3>🤝 Wrapping Up</h3>
<p>That is a wrap on this week's issue, where I explored localization with <strong>Xcode String Catalogs</strong>.
I truly believe String Catalogs are a well-designed addition that transforms the once tedious localization process into something much more streamlined and enjoyable to use!</p>
<p>Next week, I will be stepping out of my comfort zone to explore how to <strong>design an app logo</strong> for my newsletter app, <strong>without any prior design skills</strong>.
Stay tuned!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>String Catalog</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/46.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🚖 Handling Deep Links from Push Notifications in SwiftUI 🔔]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue45</link>
            <guid>45</guid>
            <pubDate>Mon, 19 May 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I am taking things further by handling deep linking from notifications. I will show you how to direct users to a specific screen when they tap a notification.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #45</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>8th</strong> edition of the <strong>&quot;Building a Newsletter App&quot;</strong> series.</p>
<p>Last week, I walked you through <a href="/issue/issue44">integrating push notifications</a> into my newsletter app and configured a provider to send them!</p>
<p>This week, I am taking things further by handling <strong>deep linking</strong> from notifications.
I will show you how to direct users to a specific screen when they tap a notification.
By default, the app opens on the initial screen, but I want users to land on the latest issue instead - let's make that happen today!</p>
<h3>🧐 Sneak Peek: Handling Deep Links</h3>
<p>Here is a glimpse of what I am aiming for - handling deep links from push notifications!</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue45/deep_links.gif&quot;
alt=&quot;Example of handling deep links from a push notification.&quot;
link=&quot;/issues/issue45/deep_links.gif&quot;
caption=&quot;Example of handling deep links from a push notification.&quot;
/&gt;</p>
<h2>The Plan</h2>
<p>The goal is simple - handle a deep link when I click on a notification. Here is the plan:</p>
<ul>
<li>Configure a custom <strong>URL type</strong></li>
<li>Understand how to create an <strong>Apple notification JSON payload</strong></li>
<li><strong>Get the data</strong> from the notification</li>
<li>Link the app's <strong>entry point</strong> with the <strong>AppDelegate</strong></li>
<li><strong>Handle deep links</strong> from the notification JSON payload</li>
</ul>
<h3>Configuring a custom URL Type</h3>
<p>To set up deep links within our Xcode project, we need to configure a custom URL scheme.
To do that, click on your project &gt; Info Tab &gt; Select URL types &gt; click the &quot;+&quot; icon.
Here, we need to fill the identifier and the URL scheme fields.
The identifier corresponds to your app bundle identifier and the URL schemes is essentially the host part of your app that this is going to listen to and it can be a string you choose.
In my case, I am going with <code>ioscoffeebreakapp</code> as my URL scheme.</p>
<p>Here is my configuration as example:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue45/url_schemes.webp&quot;
alt=&quot;Setting up an URL type in Xcode.&quot;
link=&quot;/issues/issue45/url_schemes.webp&quot;
caption=&quot;Setting up an URL type in Xcode&quot;
/&gt;</p>
<h3>Creating the JSON payload</h3>
<p>Here is how you can create an Apple notification JSON payload:</p>
<pre><code class="language-swift">{
    &quot;aps&quot; : {
       &quot;alert&quot; : {
            &quot;title&quot; : &quot;New Issue is live 🚀🚀🚀&quot;,
            &quot;body&quot; : &quot;Check issue #45 and learn how to handle deep links.&quot;
        },
        &quot;sound&quot; : &quot;default&quot;
   },
    &quot;link&quot;: &quot;ioscoffeebreakapp://issue?id=45&quot;
}
</code></pre>
<blockquote>
<p>For more information, check <a href="https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification#Create-the-JSON-payload">Apple's official documentation</a> on how to generate a remote notification.</p>
</blockquote>
<p>You can create custom keys such as my <code>&quot;link&quot;</code> property in the example above.
I am particularly interested in providing this custom key as this property tells my application what screen it should navigate to.
Here I am setting the entire deep link custom URL scheme as well as the query parameters that it expects.</p>
<blockquote>
<p>Note that custom keys need to be outside of the <code>&quot;aps&quot;</code> object.</p>
</blockquote>
<h3>Getting the Data from the Notification Payload</h3>
<p>Whenever we interact with a push notification, we can extract some data from it.
To get the data from the JSON payload, we need to parse the <code>userInfo</code> dictionary from the notification content attribute.</p>
<p>In here, we are particularly interested in the <code>&quot;link&quot;</code> property, where we will pass the deep link information.
Here is how we can do it:</p>
<pre><code class="language-swift">extension AppDelegate: UNUserNotificationCenterDelegate {

    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse
    ) async {
        if let deepLink = response.notification.request.content.userInfo[&quot;link&quot;] as? String,
           let url = URL(string: deepLink) {
            print(&quot;🔔 deep link: \(deepLink)&quot;)
            // handle deep link here.
        }
    }

    [...]
}
</code></pre>
<h3>Linking the App's entry point with the AppDelegate</h3>
<p>To link some of the functions from our <strong>SwiftUI</strong> app to our <code>AppDelegate</code>, we can create a property to assign our app to it.
Here is one way to do it:</p>
<pre><code class="language-swift">class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
    var app: iOSCoffeeBreakApp?

    [...]
}
</code></pre>
<p>Next, in our app entry point, we can assign the app reference to the <code>AppDelegate</code> in the <code>onAppear</code> method for example.</p>
<pre><code class="language-swift">@main
struct iOSCoffeeBreakApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
    @State private var tabsCoordinator = TabsCoordinator()

    var body: some Scene {  
        WindowGroup {
            AppView()
                .environment(tabsCoordinator)
                .onAppear {
                    appDelegate.app = self
                }

                [...]
        }
    }
}
</code></pre>
<h3>Handling Deep Links from the JSON Payload</h3>
<p>Now that we have a link between the two, we can handle deep links from the <code>userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse)</code> method.</p>
<pre><code class="language-swift">extension AppDelegate: UNUserNotificationCenterDelegate {

    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse
    ) async {
        if let deepLink = response.notification.request.content.userInfo[&quot;link&quot;] as? String,
           let url = URL(string: deepLink) {
            print(&quot;🔔 deep link: \(deepLink)&quot;)
            app?.handleDeeplink(from: url)
        }
    }

    [...]
}
</code></pre>
<p>The <code>handleDeepLink</code> method is defined at the app's entry point and is in charge for taking the user to the correct screen.</p>
<blockquote>
<p>I will not cover the details of the TabsCoordinator in this issue but if you want to know more about how you can integrate the Coordinator Pattern into your SwiftUI Apps, I have the right <a href="https://tiagohenriques.dev/blog/swiftui-refactor-navigation-layer-using-coordinator-pattern">article</a> for you!</p>
</blockquote>
<pre><code class="language-swift">
extension iOSCoffeeBreakApp {
    func handleDeeplink(from url: URL) {
        print(&quot;🔔 url: \(url)&quot;)
        let routeFinder = RouteFinder()
        if let route = routeFinder.findIssueRoute(from: url) {
            // switch to .issues tab
            tabsCoordinator.switchToTab(.issues)
            // push to route
            tabsCoordinator
                .issuesCoordinator
                .coordinator
                .push(route)
        }
    }
}
</code></pre>
<h3>🤝 Wrapping Up</h3>
<p>And that wraps up my guide on handling <strong>deep links</strong> using my newsletter app as an example!</p>
<p>Next week, I will dive into <strong>app localization</strong>, giving you an overview of <strong>Xcode's String Catalogs</strong> and how they simplify the process.
Stay tuned for more!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Deep Links</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/45.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨‍🚀 Setting Up and Sending Remote Push Notifications 🔔]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue44</link>
            <guid>44</guid>
            <pubDate>Mon, 12 May 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this post, I will walk through how to set up your app to receive push notifications and show how you can configure a provider to send notifications for you.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #44</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.
Can you believe this is already the <strong>7th</strong> edition of the <strong>&quot;Building a Newsletter App&quot;</strong> series? 😲
The journey isn't over yet - I still have plenty of features I would love to add!</p>
<p>Last week, I guided you on the <a href="/issue/issue43">implementation of the issue detail page</a> and how I handled navigation between screens.</p>
<p>And this week I ask you: What is the point of an <strong>iOS Newsletter app</strong> if no one knows about new issues?
If only there were a way to notify users when fresh content is available... 🤭</p>
<p>That's right! This week, I am <strong>setting up push notifications for my newsletter app</strong> 🚀.
This is a must-have feature for an application of this kind, so I must confess I was looking forward to implement it!</p>
<p>In this post, I will walk through how to <strong>set up your app to receive push notifications and show how you can configure a provider to send notifications for you</strong>.
Ready or not, Let's get this done!</p>
<h3>🧐 Sneak Peek: Receiving Push Notifications</h3>
<p>Here is a glimpse of what I am aiming for — enabling push notifications for the app!</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue44/push_notifications.webp&quot;
alt=&quot;Example of receiving a background push notification.&quot;
link=&quot;/issues/issue44/push_notifications.webp&quot;
caption=&quot;Example of receiving a background push notification.&quot;
/&gt;</p>
<h2>The Plan</h2>
<p>The goal is simple — get my newsletter app ready for push notifications. Here is the plan:</p>
<ul>
<li>Request user permission to send notifications.</li>
<li>Registering for push notifications.</li>
<li>Set up a remote notification provider.</li>
</ul>
<h3>Requesting User Permission to Send Notifications</h3>
<p>Before displaying alerts on a user's device, we must first <strong>ask their permission</strong>.
This can be done by requesting authorization with the following code:</p>
<pre><code class="language-swift">import UserNotifications

@Observable
class NotificationsManager {
    private(set) var hasPermission: Bool = false

    @MainActor
    func request() async {
        do {
            self.hasPermission = try await UNUserNotificationCenter
                .current()
                .requestAuthorization(options: [.alert, .badge, .sound])
        } catch {
            print(&quot;you can handle the error here.&quot;)
        }
    }
}
</code></pre>
<blockquote>
<p>The system prompts us to allow or deny the request only the first time - any subsequent requests won't trigger the prompt again. Once we give permission, we can proceed with registering the app to receive remote push notifications.</p>
</blockquote>
<h3>Registering for Remote Push Notifications</h3>
<p>We must register for remote push notifications in order to obtain the device token from APNs.
In a <strong>SwiftUI</strong> app, you can do this by creating a new file called <code>AppDelegate.swift</code>, define a class that conforms to <code>UIApplicationDelegate</code>, and implement the <code>application(_:didFinishLaunchingWithOptions:)</code> method.</p>
<pre><code class="language-swift">import UserNotifications

class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -&gt; Bool {
        // register to receive remote notifications
        application.registerForRemoteNotifications()

        UNUserNotificationCenter.current().delegate = self
        return true
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse
    ) async {
        print(&quot;You can interact with your notification here.&quot;)
    }
}
</code></pre>
<p>To connect the app delegate to the <strong>SwiftUI</strong> app lifecycle, we need to use the <code>UIApplicationDelegateAdaptor</code> property wrapper. Here is how you can do it:</p>
<pre><code class="language-swift">import SwiftUI

@main
struct iOSCoffeeBreakApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate

    var body: some Scene {
        WindowGroup {
            AppView()
        }
    }
}
</code></pre>
<h3>Configuring a Remote Notifications Provider</h3>
<p>There are multiple options available for handling push notifications, including building your own provider.
However, I chose <a href="https://firebase.google.com/">Firebase</a> because it is free, reliable, and easy to integrate.
<a href="https://firebase.google.com/docs/cloud-messaging">Firebase Cloud Messaging (FCM)</a> is the feature that enables push notifications.</p>
<p>Here is how to set up remote notifications and integrate <strong>Firebase</strong> into your app:</p>
<ul>
<li>Enable the Push Notifications capability in Xcode</li>
<li>Create a project in the Firebase console</li>
<li>Register an iOS App to your project</li>
<li>Add the <a href="https://github.com/firebase/firebase-ios-sdk.git">Firebase SDK</a></li>
<li>Select the <code>FirebaseMessaging</code> module from the <code>firebase-ios-sdk</code> package</li>
</ul>
<blockquote>
<p>In order to work with remote notifications you need to enroll in the <a href="https://developer.apple.com/programs/">Apple Developer Program</a>.</p>
</blockquote>
<h4>Setting Up Firebase SDK</h4>
<p>Here is how we can set up <strong>Firebase</strong> in our application's <strong>AppDelegate</strong>:</p>
<pre><code class="language-swift">[...]
import FirebaseCore

class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -&gt; Bool {        
        FirebaseApp.configure()

        [...]

        return true
    }
}
</code></pre>
<h4>Configuring an APNs Authentication Key</h4>
<p>To receive remote notifications on a device, our <strong>Firebase</strong> project needs to be configured with an <strong>authentication key</strong> or <strong>certificate</strong>.
I am using an <strong>APNs authentication key</strong> since it doesn't expire and works indefinitely after being uploaded.</p>
<blockquote>
<p>If you don't know how to create an APNs authentication key, <a href="https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns">here</a> is one way to do it.</p>
</blockquote>
<p>Once the key is created, configure it in <strong>Firebase</strong> under <code>Project Settings</code> &gt; <code>Cloud Messaging</code> &gt; <code>Apple app configuration</code>, then upload the key.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue44/apns_key.webp&quot;
alt=&quot;Uploading an APNs authentication key.&quot;
link=&quot;/issues/issue44/apns_key.webp&quot;
caption=&quot;Uploading an APNs authentication key.&quot;
/&gt;</p>
<h4>Setting Up Firebase Cloud Messaging</h4>
<p>In order to configure our project to work with <strong>Firebase Cloud Messaging</strong>, we need to set up the messaging delegate:</p>
<pre><code class="language-swift">[...]
import FirebaseMessaging

class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -&gt; Bool {        
        [...]
        
        Messaging.messaging().delegate = self

        return true
    }
}
</code></pre>
<p>Next, we need to implement the Firebase <strong>MessagingDelegate</strong> protocol.
This step is essential to connect our app with <strong>Firebase</strong> by sending the device token to <strong>Firebase's</strong> backend, enabling it to deliver notifications to the device.</p>
<pre><code class="language-swift">extension AppDelegate: MessagingDelegate {
    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        Messaging.messaging().apnsToken = deviceToken
    }
}
</code></pre>
<blockquote>
<p>Remote notifications don't work on the simulator. You need an actual device to test them.</p>
</blockquote>
<p>In order to test push notifications on a single device, we need to get the <strong>FCM</strong> registration token from our device.
Here is how you can do that:</p>
<pre><code class="language-swift">extension AppDelegate: MessagingDelegate {
    [...]

    func messaging(
        _ messaging: Messaging,
        didReceiveRegistrationToken fcmToken: String?
    ) {
        #if DEBUG
        print(&quot;🚨 FCM Token: \(fcmToken)&quot;)
        #endif
    }
}
</code></pre>
<p>Now, to create and send notifications from <strong>Firebase</strong>, just go to your <strong>Firebase console</strong>, select <strong>Messaging</strong> and then create a new push notification campaign like this:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue44/configuring_notification.webp&quot;
alt=&quot;Sending a push notification from Firebase.&quot;
link=&quot;/issues/issue44/configuring_notification.webp&quot;
caption=&quot;Sending a push notification from Firebase.&quot;
/&gt;</p>
<h3>🤝 Wrapping Up</h3>
<p>Uff 🥵! I hope that was not a lot to follow!
But with that, I have showed you how you can set up and send <strong>push notifications</strong> from <strong>Firebase</strong> to your app using my newsletter app as example.</p>
<p>Next week, I will be diving into handling background <strong>deep links</strong> from push notifications and navigating users directly to specific screens.
Stay tuned!</p>
<h3>⚠️ Important Update</h3>
<blockquote>
<p>Newsletter subscribers will receive complimentary access to the project's source code.
If you want to get the most out of this series, I highly recommend subscribing! 🤩</p>
</blockquote>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Push Notifications</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/44.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨‍🏭 Implementing the Issues Detail View 🦫]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue43</link>
            <guid>43</guid>
            <pubDate>Mon, 05 May 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[In this edition, I will walk through how I built the issues detail view and how I handled navigation between screens.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #43</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>6th</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Some weeks ago, I showed you how to <a href="/issue/issue41">test my issues view model</a> using Apple's new <a href="https://developer.apple.com/documentation/testing/">Swift Testing</a> framework.</p>
<p>This week, I am diving deeper into implementing the <strong>issue detail view</strong>.
Simply listing all newsletter issues isn't very interesting, right? 😒
Ideally, tapping on an issue should navigate to a detailed page with more information.</p>
<p>In this edition, I will walk through how <strong>I built the detail view and how I handled navigation between screens</strong>.
Let's explore the approach!</p>
<h2>🧐 Sneak Peek: Issue View</h2>
<p>I love clean and minimalist designs and I believe showing all the information in a list using <strong>sections</strong> and <strong>headers</strong> works perfectly.
Here is a glimpse of what I am aiming for with the issue view.</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue43/issueview.webp&quot;
alt=&quot;iOS Coffee Break app's issue detail view.&quot;
link=&quot;/issues/issue43/issueview.webp&quot;
caption=&quot;iOS Coffee Break app's issue detail view.&quot;
/&gt;</p>
<h2>The Plan</h2>
<p>To build the detail view, here are the things I need to do:</p>
<ul>
<li>Create the <code>IssueView</code> using mock data.</li>
<li>Allow users to open the issue in a <strong>web browser</strong>.</li>
<li>Get the <strong>articles</strong> for a given issue.</li>
<li>Add <strong>sharing</strong> functionality to let users share the content.</li>
</ul>
<h3>Implement the Issue Detail View</h3>
<p><strong>SwiftUI's</strong> list view supports sections and headers, similar to <strong>UITableView</strong> in <strong>UIKit</strong>.
To organize and structure content, you can wrap items inside a <a href="https://developer.apple.com/documentation/swiftui/section">Section</a>, optionally including a header or footer.</p>
<p>To allow users to open an issue in a web browser, a <a href="https://developer.apple.com/documentation/swiftui/link">Link</a> component can be added, passing the issue's URL as a string.</p>
<pre><code class="language-swift">struct IssueView: View {
    let issue: Issue

    var body: some View {
        List {
            Section(&quot;Title&quot;) {
                Text(issue.title)
            }

            Section(&quot;Description&quot;) {
                Text(issue.summary)
            }

            Section(&quot;Info&quot;) {
                LabeledContent(&quot;Date&quot;, value: issue.date.formatted(date: .numeric, time: .omitted))
                LabeledContent(&quot;Tag&quot;, value: issue.tags.joined(separator: &quot;, &quot;))
            }

            if let url = URL(string: issue.url) {
                Link(destination: url) {
                    Text(&quot;Check Issue #\(issue.id)&quot;)
                }
            }
        }
        .navigationTitle(&quot;Issue #\(issue.id)&quot;)
        .navigationBarTitleDisplayMode(.inline)
    }
}
</code></pre>
<h3>Extracting Articles from an Issue</h3>
<p>If you take a look at the newsletter <a href="https://www.ioscoffeebreak.com/api/feed.json">API feed</a>, you will notice that there is no direct articles property!
So, how can we retrieve them?</p>
<p>The API provides <code>content_html</code>, which contains the issue's content in <strong>markdown</strong> format.
By parsing this <strong>HTML</strong> string, we can extract article links and title.</p>
<p>To achieve this, we need to scan the <strong>HTML</strong>, find all <strong>h2</strong> elements and identify those containing <strong>a href</strong> attributes. For this, I have used the <a href="https://github.com/scinfu/SwiftSoup">SwiftSoup</a> library to efficiently scrape and parse the data.</p>
<p>Here is the code:</p>
<pre><code class="language-swift">import SwiftSoup

class IssuesConverter {
    func map(from issue: Issue) -&gt; Issue {
        guard let headers: Elements = try? SwiftSoup.parse(issue.content).select(&quot;h2&quot;) 
        else { return issue }
        var copy = issue
        var articles = [Article]()
        for header in headers.array() {
            if let link: Element = try? header.select(&quot;a&quot;).first(),
               let title = try? link.text(),
               let url = try? link.attr(&quot;href&quot;) {
                articles.append(
                    Article(
                        title: title,
                        url: url
                    )
                )
            }
        }
        copy.articles = articles
        return copy
    }
}
</code></pre>
<h3>Add Sharing Functionality</h3>
<p>To allow users to share issue content easily, we can use the <a href="https://developer.apple.com/documentation/SwiftUI/ShareLink">ShareLink</a> component in <strong>SwiftUI</strong>.
Simply pass the issue's URL as a parameter, and <strong>SwiftUI</strong> will handle the sharing options seamlessly for you.</p>
<pre><code class="language-swift">struct IssueView: View {
    let issue: Issue

    var body: some View {
        List {
            [...]
        }
        .navigationTitle(&quot;Issue #\(issue.id)&quot;)
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ShareLink(item: URL(string: issue.url)!)
        }
    }
}
</code></pre>
<blockquote>
<p>As you can see, you can wrap the ShareLink into a .toolbar component.</p>
</blockquote>
<h3>Navigating to the Issue View</h3>
<p>The final step is setting up navigation to the <code>IssueView</code>, which is simple.
In <code>IssuesView</code>, use a <a href="https://developer.apple.com/documentation/swiftui/navigationlink">NavigationLink</a> component, passing <code>IssueView</code> as the destination.</p>
<pre><code class="language-swift">struct IssuesView: View {
    [...]

    var body: some View {
        NavigationStack {
            Group {
                if vm.isLoading {
                    ProgressView()
                } else {
                    List(vm.issues) { issue in
                        NavigationLink {
                            IssueView(issue: issue)
                        } label: {
                            IssueRowView(issue: issue)
                        }
                    }
                }
            }
            .navigationTitle(&quot;Issues&quot;)

            [...]
        }
    }
}

</code></pre>
<h2>🤝 Wrapping Up</h2>
<p>With that, our issues detail view is now complete, allowing us to display information about a specific issue!</p>
<p>Next week, I will walk you through setting up <strong>push notifications</strong> for your app, using the <strong>iOS Coffee Break Newsletter application</strong> as an example.
Stay tuned!</p>
<h3>⚠️ Important Update</h3>
<p><strong>Newsletter subscribers will receive complimentary access to the project's source code</strong>.
If you want to get the most out of this series, I highly recommend subscribing! 🤩</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.artemnovichkov.com/blog/demystifying-picture-in-picture-on-ios">🪟 Demystifying Picture in Picture on iOS</a></h2>
<p>Adopting <strong>Picture in Picture (PiP)</strong> into a custom video player might appear straightforward at first, but if you have tried it yourself, you know that it turns out to be quite challenging!</p>
<p>In his latest article, <a href="https://x.com/iosartem">Artem</a> walks you through enabling Picture in Picture mode on iOS, beginning with a UIKit-based setup.</p>
<h2><a href="https://manu.show/2025-05-03-ep087-sheets-manipulation/">🤔 Sheets Manipulation</a></h2>
<p>How do you manage sheets in your SwiftUI application?</p>
<p><a href="https://x.com/manu__show">Manu's</a> latest article discusses which approach suits different situations best, <strong>enum-based</strong> vs <strong>boolean-based</strong> sheet manipulation.</p>
<h2><a href="https://manu.show/2025-04-29-ep86-localization-handling-plurals/">🌍 Localization - Pluralizations</a></h2>
<p>How do you handle String Pluralization in your app?</p>
<p>If you didn't know, <strong>String Catalogs</strong> come with built-in <strong>pluralization support</strong> — making it a much simpler and faster alternative to the old method using strings and stringsdict files.
Some weeks ago, <a href="https://x.com/manu__show">Manu's</a> published an article that walks you through how to handle plurals using String Catalogs.</p>
<h2><a href="https://nowham.dev/posts/parallelize_unit_tests/">🧘‍♂️ Parallelize Unit Tests in Your iOS App</a></h2>
<p><a href="https://x.com/No_Wham">Noam's</a> latest article explores two different approaches for running unit tests in your iOS application: one with the <strong>Xcode command-line tools and Bash</strong> and the other using <strong>Fastlane</strong>.
Each method comes with its own advantages and drawbacks so you can choose the one that aligns best with your development process!</p>
<h2><a href="https://blog.codemagic.io/automate-release-notes/">📜 Automate Release Notes Updates with Codemagic CI/CD</a></h2>
<p>Do you find it a bit tiresome to repeatedly type out the same release notes each time you submit your app for review?</p>
<p>In this article, Masaki Sato from the <a href="https://x.com/codemagicio">Codemagic</a> team shares a way to streamline that process by automatically uploading your release notes along with your app submissions to the stores.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/43.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👫 Leveraging Social Platforms to Grow the Newsletter ⬆️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue42</link>
            <guid>42</guid>
            <pubDate>Mon, 21 Apr 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I decided to share my newsletter on LinkedIn and honestly, I wish I had done it sooner! Find out why!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #42</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬!</p>
<p>This week, I decided to take a break from my <strong>series on how to build a newsletter app</strong> — can you believe we are already <strong>5</strong> episodes in? 😲</p>
<p>Instead, I kicked things off by trying out <a href="https://x.com/twannl">Antoine's</a> tip to <a href="https://www.linkedin.com/feed/update/urn:li:activity:7317588656024604672/">share my newsletter on LinkedIn</a>, and honestly, I wish I had done it sooner!
With just a few small tweaks, I was able to convert the content to fit LinkedIn's format, and the results spoke for themselves.</p>
<p>It might not seem like a lot, but simply resharing the content helped me grow nearly <strong>250 new subscribers</strong>.
It is a great reminder of how <strong>powerful marketing can be</strong>.
You might have an amazing product, but it won't go far if people don't know about it.</p>
<p><strong>Leverage your social platforms, grow your online presence</strong> — and if you are doing it right, the rest will follow naturally! 🙂</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://nowham.dev/posts/unit_test_ios_app_on_ci_withouth_fastlane/">🦉 Unit test your iOS app without Fastlane</a></h2>
<p><a href="https://x.com/No_Wham">Noam</a> took a break on his Fastlane series to share a new post on <strong>running unit tests in your iOS app using Xcode's command-line tools and Bash</strong>.</p>
<p>Bash offers a ton of flexibility, and xcodebuild isn't just for testing — it can handle building, archiving, exporting, and much more.
This approach is perfect if you are working in a CI environment where Ruby isn't available, can't install Fastlane, or simply want to understand how to do it all manually, without relying on third-party tools.</p>
<h2><a href="https://swiftrocks.com/how-im-using-ai-for-software-engineering">🕵️ How I'm using AI to improve my software engineering productivity (and why it will not steal your job)</a></h2>
<p>If you are anything like <a href="https://x.com/rockbruno_">Bruno</a>, <strong>AI</strong> has become a key tool in your everyday workflow as a software engineer.</p>
<p>That is exactly why he decided to put together a post explaining how he is been <strong>using it in his day-to-day</strong>.
He also shares his thoughts on the growing number of articles claiming AI is coming for software engineering roles.</p>
<h2><a href="https://www.artemnovichkov.com/blog/creating-mcp-servers-in-swift">🤖 Creating MCP Servers in Swift</a></h2>
<p>New <strong>LLMs</strong> seem to pop up almost every week lately — and now there is a fresh addition to the <strong>AI</strong> automation scene: <strong>Model Context Protocol (MCP)</strong>.
If you have been following the <strong>AI</strong> space, chances are you have heard this acronym a few times recently.</p>
<p>This week, <a href="https://x.com/iosartem">Artem</a> took a closer look at <strong>MCP</strong> and even built a lightweight <strong>MCP server in Swift</strong> that simply <strong>returns the current Swift version installed on your machine</strong>!</p>
<h2><a href="https://nilcoalescing.com/blog/ReactToNetworkStatusUpdatesInSwiftUI/">🚔 React to network status updates in SwiftUI</a></h2>
<p>In his latest post, <a href="https://x.com/hishnash">Matthaus</a> from <a href="https://x.com/NilCoalescing">Nil Coalescing</a> shows how to use the <strong>NWPathMonitor</strong> as an async sequence to stream real-time network status updates directly into your SwiftUI views.</p>
<p>Speaking of <strong>NWPathMonitor</strong>, I created a <a href="https://github.com/henriquestiagoo/network-monitor">Swift Package</a> some time ago that also uses this API to monitor network changes - this time by leveraging the <strong>NotificationCenter</strong> to broadcast the changes.
The examples I included were based on <strong>UIKit</strong>, but they are easy to tweak for use with <strong>SwiftUI</strong> too.</p>
<h2><a href="https://swifttoolkit.dev/posts/sake-1">🍶 Sake: Swift-powered Command Management - Part I</a></h2>
<p>Discover Sake – a Swift-based alternative to Makefiles.
Created by <a href="https://mastodon.social/@kattouf">Vasiliy Kotov</a>, it lets you define your build and automation tasks using Swift code rather than traditional shell scripts.</p>
<p>In this practical guide, <a href="https://x.com/natanrolnik">Natan</a> from <a href="https://x.com/SwiftToolkit">SwiftToolkit</a> walks you through how to use Sake to streamline tasks like <strong>linting</strong>, <strong>formatting</strong>, and more – all in pure <strong>Swift</strong>.</p>
<h2><a href="https://github.blog/enterprise-software/ci-cd/when-to-choose-github-hosted-runners-or-self-hosted-runners-with-github-actions/">🤔 When to choose GitHub-Hosted runners or self-hosted runners with GitHub Actions</a></h2>
<p><strong>GitHub</strong> just dropped a post on <strong>self-hosted</strong> vs <strong>GitHub-hosted</strong> runners.</p>
<p>With <strong>GitHub Actions</strong>, you can build out your <strong>CI/CD</strong> pipeline and automate various workflows both <strong>within and outside of GitHub</strong>.
This post breaks down the key differences, benefits, and trade-offs of each option to help your team make an informed choice when it comes to scaling and securing your automation infrastructure.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/42.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👋 Introducing Unit Tests with Swift Testing 🧪]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue41</link>
            <guid>41</guid>
            <pubDate>Mon, 14 Apr 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I will demonstrate how to test my IssuesViewModel using Apple's new Swift Testing framework.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #41</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>5th</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Last week, I discussed implementing <a href="/issue/issue40">error handling</a> by defining an <code>APIError</code> enum to represent different error types.</p>
<p>This week, I will demonstrate how to <strong>test</strong> my <code>IssuesViewModel</code> using Apple's new <a href="https://developer.apple.com/documentation/testing/">Swift Testing</a> framework.
This modern and expressive <strong>API</strong> simplifies writing tests while <strong>Xcode's</strong> improved interface provides clearer feedback on test results, making debugging and maintaining code more efficient.</p>
<h2>The Plan</h2>
<p>In a <a href="/issue/issue39">previous issue</a>, I introduced <strong>3</strong> different implementations of the <code>IssuesRepository</code> protocol, each designed for specific scenarios.
This time, I will use those implementations to test my <code>IssuesViewModel</code> under different conditions. Here is what I am covering in this week's issue:</p>
<ul>
<li>Testing the <code>IssuesViewModel</code> with <code>IssuesSuccessMockRepository</code>.</li>
<li>Testing <code>IssuesViewModel</code> with <code>IssuesEmptyMockRepository</code>.</li>
<li>Testing <code>IssuesViewModel</code> with <code>IssuesFailureMockRepository</code>.</li>
</ul>
<h3>Integrating Swift Testing into an Existing Project</h3>
<p>If you are new to testing, you have nothing to compare from, however, if you are familiar with <strong>XCTest</strong>, the <strong>Swift Testing</strong> framework introduces some changes.
Adding a <strong>Swift Testing</strong> based test to your project is simple.
If you already have a test target, just create a new <strong>Swift</strong> file, import the <strong>Testing framework</strong> and start writing your tests.</p>
<h3>Writing Tests for IssuesViewModel with Success Data</h3>
<p>In this file, we will test how the <code>IssuesViewModel</code> behaves when our repository successfully returns data.
This ensures that the <strong>view model</strong> correctly processes and presents the fetched issues.</p>
<pre><code class="language-swift">import Testing
@testable import iOS_Coffee_Break

class IssuesViewModelSuccessRepositoryTests {
    private var issuesRepository: IssuesRepository!
    private var vm: IssuesViewModel!

    init() {
        issuesRepository = IssuesSuccessMockRepository()
        vm = IssuesViewModel(issuesRepository: issuesRepository)
    }

    deinit {
        issuesRepository = nil
        vm = nil
    }
    
    @Test(&quot;Test successful response&quot;)
    func test_successful_response() async throws {
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
        await vm.getIssues()
        #expect(!vm.hasError, &quot;The view model should not have errors.&quot;)
        #expect(vm.error == nil, &quot;The view model should not have errors.&quot;)
        #expect(vm.issues.count == 2, &quot;There should be 2 elements within our issues array.&quot;)
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
    }
}
</code></pre>
<blockquote>
<p>Notice the test I just showed is essentially a function with a @Test macro applied to it!</p>
</blockquote>
<p>In the example above, I defined the <code>init</code> function within <code>IssuesViewModelSuccessRepositoryTests</code>.
The <code>Swift Testing</code> framework automatically calls this function before each test, allowing us to set up necessary dependencies like a database connection or initialize mock data.</p>
<p>Since I am using a class-based test suite, the <code>deinit</code> function helps reset the <code>IssuesRepository</code> dependency after each test.
You can think of <code>deinit</code> in <code>Swift Testing</code> as the equivalent of <code>teardown()</code> in <code>XCTest</code>, ensuring a clean test environment for every run.</p>
<h3>Writing Tests for IssuesViewModel with Empty Data</h3>
<p>In this file, we will verify how the issues <strong>view model</strong> behaves when our repository dependency does not return any data.</p>
<pre><code class="language-swift">import Testing
@testable import iOS_Coffee_Break

class IssuesViewModelEmptyRepositoryTests {
    private var issuesRepository: IssuesRepository!
    private var vm: IssuesViewModel!

    init() {
        issuesRepository = IssuesEmptyMockRepository()
        vm = IssuesViewModel(issuesRepository: issuesRepository)
    }

    [...]

    @Test(&quot;Test empty response&quot;)
    func test_empty_response() async throws {
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
        await vm.getIssues()
        #expect(!vm.hasError, &quot;The view model should not have errors.&quot;)
        #expect(vm.error == nil, &quot;The view model should not have errors.&quot;)
        #expect(vm.issues.count == 0, &quot;There should be 0 elements within our issues array.&quot;)
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
    }
}
</code></pre>
<h3>Writing Tests for IssuesViewModel with Failure Scenarios</h3>
<p>In this file, we will validate how the issues <strong>view model</strong> handles situations where the repository throws an error.</p>
<pre><code class="language-swift">import Testing
@testable import iOS_Coffee_Break

class IssuesViewModelFailureRepositoryTests {
    private var issuesRepository: IssuesRepository!
    private var vm: IssuesViewModel!

    init() {
        issuesRepository = IssuesFailureMockRepository()
        vm = IssuesViewModel(issuesRepository: issuesRepository)
    }

    [...]

    @Test(&quot;Test failure response with .failedToDecode error&quot;)
    func test_failure_response_with_failedToDecode_error() async throws {
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
        await vm.getIssues()
        #expect(vm.hasError, &quot;The view model should have errors.&quot;)
        #expect(vm.error == APIError.failedToDecode, &quot;The view model should have an .failedToDecode APIError.&quot;)
        #expect(vm.issues.count == 0, &quot;There should be 0 elements within our issues array.&quot;)
        #expect(!vm.isLoading, &quot;The view model should not be loading any data.&quot;)
    }
}
</code></pre>
<h3>Output</h3>
<p>Each time you run the tests, the console will display a clearer and more readable output, making it easier to interpret the results:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue41/tests_output.webp&quot;
alt=&quot;The outcome of the tests.&quot;
link=&quot;/issues/issue41/tests_output.webp&quot;
caption=&quot;The outcome of the tests.&quot;
/&gt;</p>
<h3>🤝 Wrapping Up</h3>
<p>And with that, we have seen the basics on how to implement tests using the <strong>Swift Testing</strong> framework.
I personally prefer this new way of writing tests and I think it makes testing in <strong>Swift</strong> much more enjoyable and intuitive.</p>
<p>Next week, I am planning to <strong>implement the detail view of an issue</strong>. Stay tuned for the update!</p>
<blockquote>
<p>By subscribing to the newsletter, you will get access to the code.</p>
</blockquote>
<p>&lt;Banner text={&quot;CURATED FROM THE COMMUNITY&quot;} /&gt;</p>
<h2><a href="https://www.swift.org/blog/introducing-swiftly_10/">​📦 Introducing Swiftly 1.0​</a></h2>
<p>Although the latest <strong>Swift</strong> version comes included with each Xcode release, there are scenarios where you might want to install <strong>Swift</strong> separately — <strong>without using Xcode</strong>.
A common case is setting up <strong>Swift</strong> on systems where <strong>Xcode is not available</strong>, like on <strong>Linux</strong>.</p>
<p>That is where <strong>swiftly</strong> comes in — a tool created by Apple for exactly this purpose.
While it has been available for some time, Apple officially released its first stable version <strong>(1.0)</strong> just two weeks ago, now with <strong>support for macOS</strong>.</p>
<h2><a href="https://nowham.dev/posts/bump_project_version_and_build_number/">⬆️ ​Bump app version and build number using Fastlane​</a></h2>
<p>Have you ever gone to submit a new TestFlight build, only to realize at the very end that you forgot to <strong>update the version or build number</strong>?</p>
<p>In his latest post, <a href="https://x.com/No_Wham">Noam</a> shares how to automate this step using <strong>Fastlane</strong>.
It is a super handy way to avoid those last-minute slip-ups and save time every time you push a new build.</p>
<h2><a href="https://www.artemnovichkov.com/blog/how-to-inspect-ipa-files">🔍 How to inspect .ipa files and secure your iOS app from common mistakes</a></h2>
<p>Do you ever wonder what is inside your favorite iOS app? Which third-party frameworks are used? What hidden resources are added to the app bundle?</p>
<p>In this guide, <a href="https://x.com/iosartem">Artem</a> walks you through <strong>inspecting <code>.ipa</code> files</strong> and digging into their internal contents.
He also points out <strong>common security mistakes</strong> and shares three key tips to help you keep sensitive data safe.
If you have never taken a look at your own app's <code>.ipa</code>, this article might just be the push you needed to start!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Swift Testing</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/41.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🧑‍🔧 Implementing Error Handling 🦺]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue40</link>
            <guid>40</guid>
            <pubDate>Mon, 07 Apr 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I am diving into error handling to my network client by creating a new enum that extends Swift's built-in Error type for better error management.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #40</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>4th</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Last week, I covered how to <a href="/issue/issue39">use mock data to implement views</a> and introduced <strong>3</strong> new implementations of the <code>IssuesLiveRepository</code> that can be used as the datasource of the <code>IssuesView</code>.</p>
<p>This week, I am diving into <strong>error handling</strong> to my network client by creating a new <strong>enum</strong> that extends <strong>Swift's</strong> built-in <strong>Error</strong> type for better error management.</p>
<h3>The Plan</h3>
<p>Today, I am going to focus on effectively <strong>handling errors</strong> in <strong>Swift</strong>. I will cover:</p>
<ul>
<li>How to <strong>declare errors</strong></li>
<li>How to <strong>throw errors</strong></li>
<li>How to <strong>catch errors</strong></li>
<li>Common <strong>error handling patterns</strong></li>
</ul>
<h3>Creating an APIError Enum</h3>
<p>Before I can throw an error, I need to make a list of all the possible errors I want to throw.
In my case, I am interested to handle network errors.</p>
<p>To do this, I need to create an <code>APIError</code> enum that represents my type of error:</p>
<pre><code class="language-swift">enum APIError: LocalizedError, Equatable {
    [...]

    case custom(error: Error)
    case failedToDecode
    case invalidStatusCode(statusCode: Int)
    case invalidUrl

    var errorDescription: String? {
        switch self {
        case .custom(let error):
            return &quot;Something went wrong: \(error.localizedDescription).&quot;
        case .failedToDecode:
            return &quot;Failed to decode.&quot;
        case .invalidStatusCode(let statusCode):
            return &quot;Status code falls into the wrong range: \(statusCode).&quot;
        case .invalidUrl:
            return &quot;URL is not valid.&quot;
        }
    }
}
</code></pre>
<h3>Updating the APIClient</h3>
<p>Next, I need to use the <code>APIError</code> and refactor the <strong>API</strong> request.
Here is how my <code>getIssues()</code> from the <code>APIClient</code> now looks like:</p>
<pre><code class="language-swift">class APIClient {
    [...]

    func getIssues() async throws -&gt; [Issue] {
        guard let url = URL(string: &quot;https://www.ioscoffeebreak.com/api/feed.json&quot;) else { 
            throw APIError.invalidUrl 
        }
        let request = URLRequest(url: url)
        let (data, res) = try await session.data(for: request)
        guard let res = res as? HTTPURLResponse, (200...300) ~= res.statusCode else {
            let statusCode = (res as? HTTPURLResponse)?.statusCode ?? 500
            throw APIError.invalidStatusCode(statusCode: statusCode)
        }
        let issuesResponse = try decoder.decode(IssuesResponse.self, from: data)
        return issuesResponse.issues
    }
}
</code></pre>
<h3>Refactoring the Issues View Model</h3>
<p>To catch a <strong>thrown error</strong> in <strong>Swift</strong> I need to use the <code>do-catch</code> statement.
Here is how my <code>IssuesViewModel</code> now looks like:</p>
<pre><code class="language-swift">@Observable
class IssuesViewModel {
    [...]

    @MainActor
    func getIssues() async {
        self.isLoading = true
        defer { self.isLoading = false }
        do {
            self.issues = try await issuesRepository.getIssues()
            self.hasError = false
            self.error = nil
        } catch let error as APIError {
            self.issues = []
            self.hasError = true
            self.error = error
        } catch {
            self.issues = []
            self.hasError = true
            self.error = .custom(error: error)
        }
    }
}
</code></pre>
<h3>🤝 Wrapping Up</h3>
<p>That wraps up this guide on <strong>handling errors</strong> by leveraging an <strong>enum</strong> that conforms to <strong>Swift's</strong> Error type for improved error management.</p>
<p>Next week, I will focus on <strong>adding unit tests</strong> to my newsletter app — covering why they matter and how to implement them effectively.
Stay tuned!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://x.com/polpielladev/status/1907484173310251065">​📦 CI/CD for Swift Packages Webinar</a></h2>
<p>Do you work with <strong>Swift Packages</strong> on a daily basis?
Or do you happen to maintain a <strong>Swift library</strong> that is installable via <strong>SPM</strong>?</p>
<p>This week, <a href="https://x.com/polpielladev">Pol Piela</a> hosted a free webinar packed with helpful tips and best practices to streamline your workflow and boost your confidence when releasing new versions of your <strong>Swift packages</strong>.
If you couldn't catch it live, no worries — chances are <strong>Pol</strong> will share the recording or related resources in his newsletter. Keep an eye out!</p>
<h2><a href="https://swiftwithmajid.com/2025/04/01/documenting-your-code-with-docc/">✍️ Documenting your code with DocC</a></h2>
<p>Writing <strong>clear documentation</strong> is more essential than ever, especially now that modular app architectures are becoming the norm.</p>
<p><a href="https://x.com/mecid">Majid</a> recently published a great article on this subject, where he walks through a simple example of how to document a function effectively.</p>
<h2><a href="https://serialcoder.dev/text-tutorials/swiftui/working-with-the-task-modifier-in-swiftui/">⏳ Working with The task modifier In SwiftUI</a></h2>
<p>It is often necessary to perform <strong>async tasks</strong> right when a view appears in SwiftUI.
One way to handle this is by creating a <strong>Task</strong> inside the <code>onAppear</code> modifier's action closure — but there is a more elegant solution.</p>
<p><a href="https://x.com/gabtheodor">Gabriel's</a> latest blog post dives into the <code>task</code> modifier in SwiftUI.
It explains how to execute async code when a view appears, walks through its various configuration options, and highlights some helpful insights.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Error Handling</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/40.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨‍🎨 Implementing Views Using Mock Data 🚧]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue39</link>
            <guid>39</guid>
            <pubDate>Mon, 31 Mar 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I am introducing additional implementations of the IssuesRepository protocol, tailored for different use cases such as mocking and testing.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #39</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>3rd</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Last week, we covered how to <a href="/issue/issue38">create and use Protocols in Swift</a> and introduced an <code>IssuesLiveRepository</code> that performs the work of a <strong>real external dependency</strong> within our app.</p>
<p>This week, I am introducing additional implementations of the <code>IssuesRepository</code> protocol, tailored for different use cases such as <strong>mocking</strong> and <strong>testing</strong>.</p>
<h3>The Plan</h3>
<p>As part of this, I will implement <strong>3</strong> additional versions of the <code>IssuesRepository</code> protocol, each designed to serve as a <strong>mock</strong> for different scenarios within our <code>IssuesView</code>.</p>
<ul>
<li><code>IssuesSuccessMockRepository</code> to handle scenarios where our <strong>mocked</strong> dependency returns data.</li>
<li><code>IssuesEmptyRepository</code> to handle scenarios where our <strong>mocked</strong> dependency doesn't return data.</li>
<li><code>IssuesFailureMockRepository</code> to handle scenarios where our <strong>mocked</strong> dependency returns an error.</li>
</ul>
<h3>Creating Additional Instances of the IssuesRepository</h3>
<p>Let's first create an <code>IssuesSuccessMockRepository</code> class that returns an array of sample issues.</p>
<pre><code class="language-swift">class IssuesSuccessMockRepository: IssuesRepository {
    func getIssues() async throws -&gt; [Issue] {
        return Issue.sample
    }
}
</code></pre>
<p>Next, I am creating <code>IssuesEmptyMockRepository</code> for the scenario that displays no issues data. Here I want to return an empty array.</p>
<pre><code class="language-swift">class IssuesEmptyMockRepository: IssuesRepository {
    func getIssues() async throws -&gt; [Issue] {
        return []
    }
}
</code></pre>
<p>Finally, I am creating <code>IssuesFailureMockRepository</code> and here, I am throwing an exception.</p>
<pre><code class="language-swift">class IssuesFailureMockRepository: IssuesRepository {
    func getIssues() async throws -&gt; [Issue] {
        throw APIError.unknownError
    }
}
</code></pre>
<h3>Making Use of our Mocks</h3>
<p>Using our <code>IssuesView</code> from previous discussions as an example, I can use the <code>#preview</code> macro to see how the view appears with the <strong>3</strong> newly implemented versions:</p>
<pre><code class="language-swift">struct IssuesView: View {
    @State var vm: IssuesViewModel

    init(vm: IssuesViewModel = IssuesViewModel()) {
        self.vm = vm
    }

    var body: some View {
        NavigationStack {
            List(vm.issues) { issue in
                IssueRowView(issue: issue)
            }
            .navigationTitle(&quot;Issues&quot;)
            .overlay {
                if vm.issues.isEmpty {
                    ContentUnavailableView(
                        &quot;No Issues&quot;,
                        systemImage: &quot;books.vertical.fill&quot;,
                        description: Text(&quot;No issues have been found.&quot;)
                    )
                }
            }
            .alert(isPresented: $vm.hasError, error: vm.error) {
                Button(&quot;Retry&quot;) {
                    Task {
                        await vm.getIssues()
                    }
                }
            }
            .task {
                await self.vm.getIssues()
            }
        }
    }
}

#Preview(&quot;Happy Path&quot;) {
    IssuesView(
        vm: IssuesViewModel(
            issuesRepository: IssuesSuccessMockRepository()
        )
    )
}

#Preview(&quot;Empty Path&quot;) {
    IssuesView(
        vm: IssuesViewModel(
            issuesRepository: IssuesEmptyMockRepository()
        )
    )
}

#Preview(&quot;Unhappy Path&quot;) {
    IssuesView(
        vm: IssuesViewModel(
            issuesRepository: IssuesFailureMockRepository()
        )
    )
}
</code></pre>
<p>Here is the output of the <code>IssuesView</code> with the <strong>3</strong> previews:</p>
<p>&lt;Images3Grid
src=&quot;/issues/issue39/happy_path.webp&quot;
alt=&quot;Issues View - Happy Path.&quot;
link=&quot;/issues/issue39/happy_path.webp&quot;
caption=&quot;Issues View - Happy Path.&quot;
src2=&quot;/issues/issue39/empty_path.webp&quot;
alt2=&quot;Issues View - Empty Path.&quot;
link2=&quot;/issues/issue39/empty_path.webp&quot;
caption2=&quot;Issues View - Empty Path.&quot;
src3=&quot;/issues/issue39/unhappy_path.webp&quot;
alt3=&quot;Issues View - Unhappy Path.&quot;
link3=&quot;/issues/issue39/unhappy_path.webp&quot;
caption3=&quot;Issues View - Unhappy Path.&quot;
/&gt;</p>
<h3>🤝 Wrapping Up</h3>
<p>With that, you can see the advantages of using <strong>mocks</strong> to design views for different scenarios.
Keep this approach in mind when writing your code to ensure it remains <strong>flexible</strong> and <strong>scalable</strong>.</p>
<p><strong>Mock</strong> data can also be incredibly useful in <strong>testing</strong>, enabling us to write tests a lot easier, and run them faster in a more predictable way as I plan to show you on future issues! Stay tuned!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://manu.show/2025-03-22-clean-storage-mac/">🐼 Freeing up space on your Mac</a></h2>
<p>If you are an <strong>iOS</strong> developer, chances are you have run into storage issues on your machine at some point — thank you <strong>Xcode</strong>!</p>
<p>This week, <a href="https://x.com/manu__show">Manu</a> put together a great guide on manually freeing up space on your <strong>Mac</strong>.
While there are external tools that can handle this for you, I promise it is an interesting read, even if you are just curious about how <strong>Xcode</strong> eats up your storage.</p>
<h2><a href="https://www.jessesquires.com/blog/2025/03/24/automate-perfect-mac-screenshots/">🧘‍♂️ How to automate perfect screenshots for the Mac App Store</a></h2>
<p><a href="https://x.com/jesse_squires">Jesse</a> recently explored ways to automate <strong>macOS</strong> screenshots, finding far fewer options compared to <strong>iOS</strong>.</p>
<p>He put his findings into an article, detailing his workflow for generating <strong>Mac</strong> app screenshots with minimal manual effort.
If you have faced the same challenge, be sure to check it out!</p>
<h2><a href="https://developer.apple.com/tutorials/instruments">🔎 Profiling apps using Instruments</a></h2>
<p>Not quite sure how to use Apple's <strong>Instruments</strong> tool yet?</p>
<p><strong>Apple</strong> just released an in-depth, 1.5-hour tutorial on profiling apps with <strong>Instruments</strong> — an invaluable resource for anyone looking to get started!
If you are interested but unsure where to begin, this is the perfect guide.
It is definitely on my watch list!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Protocols</category>
            <category>Mocks</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/39.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🥞 Creating and Using Protocols in Swift 🐼]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue38</link>
            <guid>38</guid>
            <pubDate>Mon, 24 Mar 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I want to dive into protocols and the advantages of adopting them!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #38</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and to the <strong>2nd</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Last week, we covered how to <a href="/issue/issue37">parse JSON using the Codable protocol</a> and implemented a real world use case that fetches and decodes data from my newsletter <a href="https://www.ioscoffeebreak.com/api/feed.json">API feed</a>.</p>
<p>This week, I want to dive into <strong>protocols</strong> and the advantages of adopting them.
As part of this, I will be refactoring my view model by replacing my <code>APIClient</code> by an <code>IssuesLiveRepository</code> class that conforms to a <strong>protocol</strong> we will define.</p>
<p>This will help improve <strong>flexibility</strong>, <strong>maintainability</strong> and <strong>testability</strong> in the code.</p>
<p>Let's explore how to implement this approach!</p>
<h3>What is a Protocol?</h3>
<p>In <strong>Swift</strong>, <strong>protocols</strong> act as blueprints, defining the expected behavior of a data type while ensuring consistency across code.</p>
<p>They have many <strong>real-world</strong> applications, such as:</p>
<ul>
<li><strong>Dependency Injection</strong>: Defining interfaces for dependencies makes testing and decoupling easier.</li>
<li><strong>UI Component Design</strong>: Protocols help create reusable UI elements.</li>
<li><strong>Networking</strong>: They establish interfaces for HTTP requests, simplifying mocking and testing.</li>
<li><strong>Delegation</strong>: A key pattern in iOS, protocols define delegate responsibilities, enabling flexible communication between objects.</li>
</ul>
<h3>Defining a Protocol</h3>
<p>Let's start by creating an <code>IssuesRepository</code> protocol that outlines a single method, responsible for returning an array of <code>Issue</code> objects.
That is all we need for our example.</p>
<pre><code class="language-swift">protocol IssuesRepository {
    func getIssues() async throws -&gt; [Issue]
}
</code></pre>
<h3>Conforming to the Protocol</h3>
<p>Now, let's create an <code>IssuesLiveRepository</code> class that adheres to the <code>IssuesRepository</code> protocol.
There is only one method to implement and it is the <code>getIssues()</code> function.
Here, we call the <code>getIssues()</code> method from the <code>APIClient</code> that returns an array of issues.</p>
<pre><code class="language-swift">class IssuesLiveRepository: IssuesRepository {
    private let apiClient: APIClient = APIClient()

    func getIssues() async throws -&gt; [Issue] {
        return await apiClient.getIssues()
    }
}
</code></pre>
<h3>Making use of the Protocol</h3>
<p>In our view model, we define a property of type <code>IssuesRepository</code>.
Using <strong>dependecy injection</strong>, we can pass in any instance that conforms to this protocol, making the code more modular, easier to test, and reducing tight coupling between components.</p>
<pre><code class="language-swift">@Observable
class IssuesViewModel {
    private(set) var issues: [Issue] = []
    private let issuesRepository: IssuesRepository

    init(issuesRepository: IssuesRepository = IssuesLiveRepository()) {
        self.issuesRepository = issuesRepository
    }

    @MainActor
    func getIssues() async {
        do {
            self.issues = try await issuesRepository.getIssues()
        } catch {
            print(&quot;Error to be handled here: \(error)&quot;)
        }
    }
}
</code></pre>
<h3>🤝 Wrapping Up</h3>
<p>While <strong>protocols</strong> offer a powerful way to enhance functionality, it is essential to consider alternative approaches that might better suit specific use cases.
As with many aspects of programming, there is no absolute <strong>right</strong> or <strong>wrong</strong> choice — each solution comes with its <strong>own tradeoffs</strong>.</p>
<p>Hopefully, this issue has provided insight into different ways to leverage <strong>protocols</strong> effectively and helped you weigh the benefits using them.</p>
<p>In future issues, I plan to introduce additional implementations of the <code>IssuesRepository</code> protocol, tailored for different use cases such as <strong>mocking</strong> and <strong>testing</strong>. Stay tuned!</p>
<h3>References</h3>
<ul>
<li><a href="https://medium.com/@mumensh/the-power-of-protocols-in-swift-4cffcfa62ab1">The Power of Protocols in Swift</a></li>
<li><a href="https://www.swiftbysundell.com/articles/combining-protocols-in-swift/">Combining protocols in Swift</a></li>
</ul>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://arifinfrds.com/2025/03/13/dependency-inversion-principle-dip-in-ios-swift/">🐙 Dependency Inversion Principle (DIP) in iOS Swift</a></h2>
<p>Have you come across the <strong>Dependency Inversion Principle (DIP)</strong>?
If not, it is a fundamental concept in software development that helps create flexible and maintainable code.</p>
<p>In this article, <a href="https://x.com/arifinfrds">Arifin</a> dives into the <strong>DIP</strong>, covering its origins, the challenges of tight coupling, and various techniques for implementing it effectively in <strong>Swift</strong>.</p>
<h2><a href="https://www.scottberrevoets.com/2025/03/15/composing-a-resume-in-markdown/">✍️ Composing a Resume in Markdown</a></h2>
<p>This week, I came across an amazing tool that I am excited to try out!
<strong>Updating a resume</strong> can be a tedious task, but since it is essentially a text-based document, it can be easily automated using <strong>Markdown</strong>.</p>
<p><a href="https://hachyderm.io/@ScottBerrevoets">Scott</a> wrote a insightful article explaining how to create a resume in <strong>Markdown</strong>, convert it to <strong>HTML</strong>, style it with <strong>CSS</strong> and then generate a <strong>PDF</strong> — making the entire process much more efficient!</p>
<h2><a href="https://www.fline.dev/solving-swift-macro-trust-issues-in-xcode-cloud-builds/">🆗 Solving Swift Macro Trust Issues in Xcode Cloud Builds</a></h2>
<p>If you have used a <strong>macro</strong> locally, you might have noticed that <strong>Xcode</strong> prompts you with a dialog asking for trust confirmation before executing the <strong>macro's</strong> package.
This becomes an issue in automated setups like <strong>Xcode Cloud</strong>, where there is no way to manually approve the prompt.</p>
<p>In his latest article, <a href="https://x.com/Jeehut">Cihat</a> explains how to set up a simple <code>post-clone</code> script to disable <strong>Xcode's macro</strong> fingerprint validation, allowing you to bypass the trust requirement.</p>
<h2><a href="https://swifttoolkit.dev/posts/deploy-fly-railway">☁️ Deploying a Swift Server App to Fly.io and Railway</a></h2>
<p>For <strong>iOS</strong> developers, deploying a <strong>Server-Side Swift</strong> app can feel a bit overwhelming!</p>
<p>In this post, <a href="https://x.com/natanrolnik">Natan</a> from <a href="https://x.com/SwiftToolkit">SwiftToolkit</a> walks you through deploying a <strong>Vapor</strong> app on two platforms — <strong>Fly.io</strong> and <strong>Railway</strong> — both of which let you skip the hassle of installing <strong>Docker</strong> on your machine.</p>
<p>A few years back, I built a <a href="https://github.com/henriquestiagoo/foods-vapor-api">food-related 🍏🍕🍦 web API</a> using <strong>Swift</strong> and <strong>Vapor</strong>, deploying it on <strong>Fly.io</strong>.
At the time, I faced some challenges with the free tier as my sample project grew, but the deployment process was so effortless that it felt almost like cheating.
Maybe I will give it another try!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Protocols</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/38.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🥷🏻 Parsing JSON using the Codable Protocol 📋]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue37</link>
            <guid>37</guid>
            <pubDate>Mon, 17 Mar 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[Welcome to the 1st issue of the 'Building the iOS Coffee Break App' series! To kick things off, I will start with a beginner-friendly topic: parsing JSON using the Codable protocol.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #37</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬</p>
<p>If you have been following the <strong>newsletter</strong>, you should know that I have decided to build an app for it and document the process!
I am glad to welcome you to the <strong>1st</strong> issue of the <strong>&quot;Building a Newsletter App&quot;</strong> series!</p>
<p>Based on last week's survey, I now have a better understanding of what topics interest my readers the most.
To kick things off, I will start with a beginner-friendly topic: <strong>parsing JSON using the Codable protocol</strong>.</p>
<p>As the app evolves and becomes more complex, I will introduce more advanced topics!</p>
<p>Hope you enjoy ✌️!</p>
<h3>🧐 Sneak Peek: Issues View</h3>
<p>Here is a glimpse of what I am aiming for with the issues view — a straightforward list displaying all past newsletter issues in a clean and accessible way.</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue37/issues_view.webp&quot;
alt=&quot;Issues View.&quot;
link=&quot;/issues/issue37/issues_view.webp&quot;
caption=&quot;Issues View.&quot;
/&gt;</p>
<h2>The Plan</h2>
<p>Here are the steps I need to perform to get this done:</p>
<ul>
<li>Define the <strong>Issue</strong> struct and ensure it conforms to the <strong>Codable</strong> protocol.</li>
<li>Retrieve issue data from the newsletter <a href="https://www.ioscoffeebreak.com/api/feed.json">API feed</a>.</li>
<li><strong>Decode</strong> the fetched data into an array of <strong>Issue</strong> objects.</li>
<li>Use the decoded data to <strong>populate</strong> the view.</li>
</ul>
<h3>The Codable Protocol</h3>
<p>The <a href="https://developer.apple.com/documentation/swift/codable">Codable</a> protocol in <strong>Swift</strong> simplifies data conversion between <strong>Swift</strong> types and formats like <strong>JSON</strong> or <strong>XML</strong>.
It merges two protocols: <a href="https://developer.apple.com/documentation/swift/encodable">Encodable</a> (for encoding <strong>Swift</strong> objects) and <a href="https://developer.apple.com/documentation/swift/decodable">Decodable</a> (for decoding external data).</p>
<p>By making <code>Issue</code> conform to <strong>Codable</strong>, we can seamlessly encode and decode instances to and from <strong>JSON</strong>, making it easy to fetch and store data in a structured format.</p>
<pre><code class="language-swift">struct Issue: Hashable, Codable, Identifiable {
    let id: String
    let content: String
    let url: String
    let title: String
    let summary: String
    let date: Date
    let author: Author
    let tags: [String]
}
</code></pre>
<blockquote>
<p>The only requirement of declaring a Codable is that all of its stored properties must also be Codable.</p>
</blockquote>
<h3>Mapping JSON Keys with CodingKeys</h3>
<p>Sometimes, <strong>JSON</strong> keys don't match your <strong>Swift</strong> property names.
The <strong>CodingKeys</strong> enum helps map them correctly.</p>
<pre><code class="language-swift">struct Issue: Hashable, Codable, Identifiable {
    [...]

    enum CodingKeys: String, CodingKey {
        case id, url, title, summary, author, tags
        case content = &quot;content_html&quot;
        case date = &quot;date_modified&quot;
    }
}
</code></pre>
<blockquote>
<p>If a required field is missing in the JSON, decoding will fail unless you handle it properly by providing default values or making the property optional.</p>
</blockquote>
<p>Here, the <code>content</code> property corresponds to <code>content_html</code> in the <strong>JSON</strong>, and <code>date</code> corresponds to <code>date_modified</code>.</p>
<h3>Decoding from JSON</h3>
<p>By making custom types like <code>Issue</code> and <code>Author</code> conform to <strong>Codable</strong>, we enable encoding and decoding between <strong>Swift</strong> objects and data formats like <strong>JSON</strong>.</p>
<p>In this case, <a href="https://developer.apple.com/documentation/foundation/jsondecoder">JSONDecoder</a> is used to transform a <strong>JSON</strong> string into its equivalent model type in <strong>Swift</strong>.</p>
<pre><code class="language-swift">class APIClient {
    [...]

    func getIssues() async -&gt; [Issue] {
        guard let url = URL(string: &quot;https://www.ioscoffeebreak.com/api/feed.json&quot;) else { return [] }
        let request = URLRequest(url: url)
        do {
            let (data, _) = try await session.data(for: request)
            let issuesResponse = try decoder.decode(IssuesResponse.self, from: data)
            return issuesResponse.issues
        } catch {
            print(&quot;Error fetching issues: \(error)&quot;)
            return []
        }
    }
}
</code></pre>
<h3>🤝 Wrapping Up</h3>
<p>And with that, we have covered how to conform to the <strong>Codable</strong> protocol, define <strong>CodingKeys</strong>, and implement custom <strong>decoding</strong> methods.</p>
<p>By understanding these concepts, you can efficiently work with your data models, ensuring consistent <strong>encoding</strong> and <strong>decoding</strong> for external formats like <strong>JSON</strong>.</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.youtube.com/watch?v=-4Kfew95lww">💪 The Power of Consistency: a Path to Indie Development - Pol Piella</a></h2>
<p><a href="https://x.com/twannl">Antoine's</a> latest episode of the <strong>Going Indie Podcast</strong> features <a href="https://x.com/polpielladev">Pol Piella</a>, an <strong>iOS</strong> dev and content creator I have been following for a while — especially when I need insights on <strong>CI/CD</strong> topics!</p>
<p>As soon as it was announced, I knew I had to highlight it in the newsletter.
<strong>Pol's</strong> journey has been a huge inspiration for me in building a public profile and starting to create and share content — big kudos to him 👏!</p>
<h2><a href="https://www.jessesquires.com/blog/2025/03/10/swiftpm-schemes-in-xcode/">✂️ How to remove unwanted Swift Package schemes in Xcode</a></h2>
<p>I bet you have been annoyed by random <strong>package schemes</strong> being listed in your Xcode project!</p>
<p>In his latest article, <a href="https://x.com/jesse_squires">Jesse</a> shares a solution to clean up those unwanted <strong>Swift package schemes in Xcode</strong>.
He even provides a handy script that you can integrate into your build process or run manually whenever needed!</p>
<h2><a href="https://swifttoolkit.dev/posts/git-hooks">🤝 Git Hooks in Swift</a></h2>
<p><strong>Swift</strong> as a <strong>Git Hook</strong>? Did I read that right?</p>
<p>In his latest post on <a href="https://x.com/SwiftToolkit">Swift Toolkit</a>, <a href="https://x.com/natanrolnik">Natan</a> walks through setting up <strong>Git hooks</strong> in a project.
He starts with a basic bash script and then demonstrates how to implement them in <strong>Swift</strong> — both as a script and as a compiled executable.</p>
<h2><a href="https://vision.rodeo/tags/conference/">🥶 ARCtic iOS conference 2025</a></h2>
<p>If <a href="https://arcticonference.com/">ARCtic Conference</a> was high on your list this year but you couldn't make it, here are some good news!</p>
<p><a href="https://mastodon.ie/@donovanh">Daniel</a> has put together a special page on his blog where he shares detailed notes from each talk.
It is unclear if the sessions will be publicly available, but in the meantime, you can check out his insights from the talks he enjoyed the most!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <category>Codable</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/37.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👨🏼‍🍳 Turning the Newsletter into an actual App! 📱]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue36</link>
            <guid>36</guid>
            <pubDate>Mon, 10 Mar 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[I am planning to turn the newsletter into an actual app! Throughout this process, I will document everything, from the initial concept to launching it on the App Store. Stay tuned!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #36</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬</p>
<p>The recent newsletter issues, where I built a sample app to demonstrate <strong>iOS 18's new tab APIs</strong>, got me thinking — I really like the idea of turning the newsletter into an <strong>actual app</strong>. Would you use it? 🤔</p>
<p>Throughout this process, I will document everything, from the <strong>initial concept</strong> to <strong>launching it on the App Store</strong>.
This way, I can reach developers of all experience levels, from beginners to seasoned professionals, while sharing insights on design and implementation.</p>
<h3>What Should It Include?</h3>
<ul>
<li>A complete list of all issues</li>
<li>A detailed view for each issue</li>
<li>A section to bookmark and access your favorite issues</li>
<li>Push notifications for new issue releases</li>
<li>Handling deep links</li>
<li>Interactive widgets</li>
<li>Additional features to be added in the future ...</li>
</ul>
<h3>Series Overview</h3>
<p>I am sharing a <a href="https://form.typeform.com/to/md0SXaqC">form</a> where subscribers and readers can suggest topics they would like covered in this series. Here are some of my initial ideas:</p>
<ul>
<li><strong>Parsing JSON</strong> using the <strong>Codable</strong> protocol</li>
<li>How to create and use <strong>protocols</strong></li>
<li>Implementing <strong>views</strong> using <strong>mock data</strong></li>
<li>Designing a scalable <strong>API client</strong></li>
<li>Using <strong>structured concurrency</strong> with <strong>async-await</strong></li>
<li>Implementing <strong>error handling</strong></li>
<li>Writing <strong>unit tests</strong></li>
<li>Persisting data with <strong>Swift Data</strong></li>
<li><strong>Distributing</strong> the app to the <strong>App Store</strong></li>
<li>And more to come...</li>
</ul>
<h3>⚠️ Important Update</h3>
<p>All resources will remain <strong>free</strong>, as that has been my goal from the start.
Creating content takes <strong>time</strong> and <strong>effort</strong>, and it is made possible thanks to the support of <strong>sponsors</strong>.
A big shoutout to <a href="https://proxyman.com/">Proxyman</a> for believing in the project and sponsoring both these and upcoming issues!</p>
<p>However, only <strong>subscribers</strong> of the <strong>newsletter</strong> will have access to the code of this series!
If you want to get the most out of this series, I highly recommend <strong>subscribing</strong>!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://manu.show/2025-03-06-your-problem-solving-ability/">🧠 Your Problem Solving Ability</a></h2>
<p>&quot;<strong>Problem solving</strong> is the foundation of software development.&quot;</p>
<p>This week, <a href="https://x.com/manu__show">Manu</a> shared an insightful article on a non-technical yet crucial topic: the <strong>importance of problem-solving</strong>.
Arguably one of the most valuable skills for any developer, this article should make you dive into a moment of self-reflection.
It certainly did for me!</p>
<h2><a href="https://swifttoolkit.dev/posts/r-pi">🍓 Swift on Raspberry Pi: Building Natively and Cross Compiling</a></h2>
<p>Did you know that with <strong>Swift 6</strong>, you can now compile on <strong>macOS</strong> and run directly on a <strong>Raspberry Pi</strong> — no Docker required?</p>
<p>This week, <a href="https://x.com/natanrolnik">Natan</a> from <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> shared an in-depth guide covering everything from setting up the Pi to native builds and cross-compilation from a Mac.
I can already imagine all the exciting projects I could run on my Raspberry Pi!</p>
<h2><a href="https://arifinfrds.com/2025/03/03/understanding-the-liskov-substitution-principle-lsp-in-swift/">🙆‍♂️ Understanding the Liskov Substitution Principle (LSP) in Swift</a></h2>
<p>Have you heard about the <a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov Substitution Principle (LSP)</a>?
If not, this principle states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.</p>
<p>In this article, <a href="https://x.com/arifinfrds">Arifin</a> breaks down this principle and shows how to apply it in <strong>Swift</strong>, by implementing a <strong>mock</strong> and a <strong>real</strong> implementation that can be used interchangeably.</p>
<h2><a href="https://x.com/swift_leeds/status/1896488547160383811">🎤 Call For Speakers</a></h2>
<p>Last year, I attended <strong>Swift Leeds</strong> and it was my first-ever <strong>iOS</strong> conference experience!</p>
<p>If you are thinking about applying as a speaker, great news — <strong>Swift Leeds' Call for Speakers</strong> is now open until April 30th.
They actively encourage new speakers, and many from last year delivered their first-ever talk at the event.
This could be the perfect opportunity for you to get started!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Building a Newsletter App</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/36.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🥸 Using UIKit's New UITab Class with Sidebar on iOS 18 👌]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue35</link>
            <guid>35</guid>
            <pubDate>Mon, 03 Mar 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I plan to rewrite the sample newsletter app using UIKit, demonstrating how to implement the same tab bars and sidebar functionalities for those still working with UIKit in their projects.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #35</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Last week, I implemented a <a href="/issue/issue34">sample application of the newsletter</a> to showcase how you can use <strong>iOS 18's</strong> new <a href="https://developer.apple.com/documentation/swiftui/tabview">TabView</a> with a <strong>sidebar</strong> in <strong>SwiftUI.</strong></p>
<p>This week, I plan to rewrite last week's application using <strong>UIKit</strong>, demonstrating how to implement the same functionality for those still working with <strong>UIKit</strong> in their projects.</p>
<p>Let's see how to get it done!</p>
<h2>UIKit Integration</h2>
<p>In <strong>UIKit</strong>, managing and customizing tabs is simple:</p>
<ul>
<li><strong>UITabBarController</strong>: Use the tabs property with <a href="https://developer.apple.com/documentation/uikit/uitab">UITab</a> options like <a href="https://developer.apple.com/documentation/uikit/uisearchtab">UISearchTab</a>.</li>
<li><strong>Adjusting modes</strong>: Set <a href="https://developer.apple.com/documentation/uikit/uitabbarcontroller/mode-swift.enum/tabbar">UITabBarController.Mode.tabBar</a> for a standard tab bar or configure it for a sidebar layout.</li>
<li><strong>SwiftUI equivalents</strong>: Convert TabSections into <a href="https://developer.apple.com/documentation/uikit/uitabgroup">UITabGroup</a>, and use <code>sidebarActions(content:)</code> instead of <code>sectionActions</code>.</li>
<li><strong>Drag and drop support</strong>: Implement <a href="https://developer.apple.com/documentation/uikit/uitabbarcontrollerdelegate">UITabBarControllerDelegate</a> to handle drag-and-drop interactions effectively.</li>
</ul>
<h3>Setting Up the Tabs</h3>
<p>We need to create a <strong>UITabBarController</strong> and assign an array of <a href="https://developer.apple.com/documentation/uikit/uitab">UITab</a> options like <a href="https://developer.apple.com/documentation/uikit/uisearchtab">UISearchTab</a> objects to its <strong>tabs</strong> property.
To add a search tab, we just need to create a <a href="https://developer.apple.com/documentation/uikit/uisearchtab">UISearchTab</a> instance and add it to the tabs array.</p>
<pre><code class="language-swift">class AppViewController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Assign an array of tabs.
        self.tabs = [
            UITab(
                title: &quot;Issues&quot;,
                image: UIImage(systemName: &quot;book&quot;),
                identifier: &quot;issues&quot;
            ) { _ in
                 // Return the view controller that the tab displays.
                 UIHostingController(rootView: IssuesView())
            },
            UITab(
                title: &quot;About&quot;,
                image: UIImage(systemName: &quot;person&quot;),
                identifier: &quot;about&quot;
            ) { _ in
                 // Return the view controller that the tab displays.
                UIHostingController(rootView: AboutView())
            },
            // Create a search tab.
            UISearchTab { _ in
                UIHostingController(rootView: SearchArticlesView())
            }
        ]
    }
}

</code></pre>
<h3>Integrate the Tab bar and Sidebar</h3>
<p>To enable users to switch between a traditional <strong>tab bar</strong> and a <strong>sidebar</strong>, we can control how the system presents your tabs by configuring the <strong>mode</strong> property of the <strong>UITabBarController</strong> object.</p>
<pre><code class="language-swift">override func viewDidLoad() {
    super.viewDidLoad()

    [...]

    // Enable the sidebar.
    self.mode = .tabSidebar
}
</code></pre>
<blockquote>
<p>By default, the system presents the sidebar in landscape orientation and hides it in portrait orientation, however, you can toggle between the tab bar and sidebar in either orientation. You can also programmatically show and hide the sidebar by setting its <code>isHidden</code> property.</p>
</blockquote>
<p>Here is the final result:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue35/ioscoffeebreak_tabbar_sidebar_uikit.gif&quot;
alt=&quot;iOS Coffee Break Newsletter UIKit sample app.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue35/ioscoffeebreak_tabbar_sidebar_uikit.gif&quot;
caption=&quot;iOS Coffee Break Newsletter UIKit sample app.&quot;
/&gt;</p>
<blockquote>
<p>To explore the full implementation of the sample application, visit the <a href="https://github.com/henriquestiagoo/tab-bar-sidebar/tree/uikit">repository on GitHub</a>.</p>
</blockquote>
<p>The improvements to tabs and sidebars in <strong>iPadOS</strong> and other <strong>Apple</strong> platforms provide greater flexibility and usability for app development.
Whether you are working with <strong>SwiftUI</strong> or <strong>UIKit</strong>, I am sure these updates simplify the process of building seamless, intuitive user interfaces!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.manu.show/2025-02-27-simple-modularization-setup/">🧱 Simple Modularization Setup for a New App</a></h2>
<p><strong>Modularizing</strong> an app from the get-go has many benefits!
This week, <a href="https://x.com/manu__show">Manu</a> shared a straightforward yet effective approach to modularizing your <strong>iOS</strong> app using Swift Package Manager's local packages that provides a good balance between structure and simplicity.</p>
<p>In fact, at work, we recently migrated a <strong>monolithic</strong> codebase to a <strong>modularized</strong> solution with <strong>Swift Packages</strong>, which significantly <strong>improved our build and compilation times</strong>, so I could not recommend it more!</p>
<h2><a href="https://www.artemnovichkov.com/blog/music-recognition-with-shazam-kit">🎸 Music recognition with ShazamKit</a></h2>
<p><strong>ShazamKit</strong> opens up exciting possibilities for integrating <strong>music recognition</strong> into your app!</p>
<p>I really enjoy <a href="https://x.com/iosartem">Artem's</a> writing style, and this time, he put together a great guide on setting up <strong>ShazamKit</strong>, detecting songs, and managing a library of identified tracks.
If you are working with music recognition, this resource could be incredibly valuable!</p>
<h2><a href="https://www.swiftjectivec.com/swift-enums-as-lighweight-view-models/">🥋 An Ode to Swift Enums: The View Models That Could</a></h2>
<p><strong>Swift Enums</strong> are an essential tool in every <strong>iOS</strong> developer's toolkit!
Actually, they are one of my favorite features in <strong>Swift</strong>, offering a powerful way to write more expressive and efficient code.</p>
<p>Using a basketball practice planner app as an example, <a href="https://x.com/jordanmorgan10">Jordan</a> dives into the versatility of <strong>Swift enums</strong>, demonstrating how he tackled different scenarios using only this type.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Tab bar</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/35.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[😎 Using SwiftUI's Improved TabView with Sidebar on iOS 18 🙌]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue34</link>
            <guid>34</guid>
            <pubDate>Mon, 24 Feb 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I want to explore the iOS 18's new TabView feature and share insights into how Apple manages tab bars and sidebars with the latest SwiftUI APIs.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #34</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Our current sprint at work includes a significant revamp of our app for <strong>iPads</strong>.
One of the most exciting updates is <strong>iOS 18's</strong> new <a href="https://developer.apple.com/documentation/swiftui/tabview">TabView</a>, which places the tab bar at the top of the screen with text-only items, while on <strong>iPhones</strong>, the traditional tab bar remains unchanged.</p>
<p>Beyond the visual updates, <strong>Apple</strong> has also introduced new functionality — the <strong>tab bar</strong> can now expand into a <strong>sidebar</strong>, offering a more structured navigation experience with a detailed hierarchy of items.</p>
<h2>SwiftUI Improvements</h2>
<p><strong>SwiftUI</strong> introduces new capabilities for managing <strong>tabs</strong> and <strong>sidebars</strong> more efficiently:</p>
<ul>
<li><strong>Simplified syntax:</strong> Use <a href="https://developer.apple.com/documentation/swiftui/tabview">TabView</a> with <a href="https://developer.apple.com/documentation/swiftui/view/tabviewstyle(_:)">TabViewStyle</a> to create tabs.</li>
<li><strong>Enhanced roles:</strong> Leverage special <a href="https://developer.apple.com/documentation/swiftui/tabrole">tab roles</a>, such as <a href="https://developer.apple.com/documentation/swiftui/tabrole/search">.search</a>.</li>
</ul>
<h2>The Plan</h2>
<p>This week, I want to explore this new <strong>SwiftUI</strong> improvement and share insights into how <strong>Apple</strong> manages <strong>tab bars</strong> and <strong>sidebars</strong> with the latest <strong>SwiftUI</strong> APIs.
To demonstrate, I have built a sample app of the newsletter featuring multiple tabs like <strong>&quot;Issues&quot;</strong>, <strong>&quot;About&quot;</strong> and <strong>&quot;Search&quot;</strong>.
When displayed as a sidebar, these tab items become into section headings instead.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue34/tabars.webp&quot;
alt=&quot;How the tab bar looks on iPadOS 18.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue34/tabars.webp&quot;
caption=&quot;How the tab bar looks on iPadOS 18.&quot;
priority={true}
/&gt;</p>
<h3>Setting Up the TabView</h3>
<p>The <strong>AppView</strong> component is responsible for rendering the tabs.
Here you can see how the Search tab differs from the others by using a <code>.search</code> tab role.</p>
<pre><code class="language-swift">enum Tabs: Equatable, Hashable {
    case about
    case issues
    case search
}

struct AppView: View {
    @State private var selectedTab: Tabs = .issues

    var body: some View {
        TabView(selection: $selectedTab) {
            Tab(&quot;Issues&quot;, systemImage: &quot;book&quot;, value: .issues) {
                IssuesView()
            }

            Tab(&quot;About&quot;, systemImage: &quot;person&quot;, value: .about) {
                AboutView()
            }

            Tab(value: .search, role: .search) {
                SearchArticlesView()
            }
        }
    }
}
</code></pre>
<h3>Enabling Sidebar Toggling</h3>
<p>To allow users to switch our <strong>tab bar</strong> into a <strong>sidebar</strong>, we need to apply the <code>tabViewStyle</code> view modifier to the <code>TabView</code> as follows:</p>
<pre><code class="language-swift">var body: some View {
    TabView(selection: $selectedTab) {
      // tabs and sections...
    }
    .tabViewStyle(.sidebarAdaptable)
}
</code></pre>
<p>Here is the final result:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue34/ioscoffeebreak_tabbar_sidebar_swiftui.gif&quot;
alt=&quot;iOS Coffee Break Newsletter SwiftUI sample app.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue34/ioscoffeebreak_tabbar_sidebar_swiftui.gif&quot;
caption=&quot;iOS Coffee Break Newsletter sample app with iOS 18 new tabviews&quot;
/&gt;</p>
<blockquote>
<p>To explore the full implementation of the sample application, visit the <a href="https://github.com/henriquestiagoo/tab-bar-sidebar/tree/swiftui">repository on GitHub</a>.</p>
</blockquote>
<p>Next week, I plan to migrate this week's sample app to <strong>UIKit</strong>, leveraging built-in APIs like <a href="https://developer.apple.com/documentation/uikit/uitab">UITab</a> and <a href="https://developer.apple.com/documentation/uikit/uisearchtab">UISearchTab</a>.
Stay tuned for the update!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.donnywals.com/newsletters/w9d40koOtJTfzLEl5Y6r7g/">🏠 How much architecture do you really need?</a></h2>
<p>How much architecture does a <strong>SwiftUI</strong> app really need? Should we strictly follow established patterns, or is a more flexible approach better?</p>
<p>Recently, the debate around <strong>SwiftUI</strong> and <strong>MVVM</strong> has resurfaced, and this week, <a href="https://x.com/DonnyWals">Donny</a> shares his perspective on the topic.
And what about you, do you still rely on <strong>MVVM</strong>, or have you adopted a different architectural style that works best for your projects?</p>
<h2><a href="https://bryce.co/undebuggable/">🔬 Debugging An Undebuggable App</a></h2>
<p>Recently, a friend from work shared with me this article by <a href="https://x.com/brycebostwick1">Bryce</a> where he debugs a regular old widget app and I immediately knew that I wanted to feature it in the newsletter.</p>
<p>While <strong>debugging</strong> and <strong>reverse engineering</strong> aren't topics I typically cover, I highly recommend following <strong>Bryce's</strong> work if you are interested in diving deeper into these areas.</p>
<h2><a href="https://arifinfrds.com/2025/02/18/open-closed-principle-ocp-in-swift-using-decorator-pattern/">🔐 Open/Closed Principle (OCP) in Swift using Decorator Pattern</a></h2>
<p>Have you heard about the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open/Closed Principle (OCP)</a>?
If not, this principle encourages building systems where new functionality can be added without altering existing code.</p>
<p>In this article, <a href="https://x.com/arifinfrds">Arifin</a> breaks down the <strong>Open/Closed Principle</strong> and shows how to apply it in <strong>Swift</strong>.
Using practical examples, he highlights the power of the <strong>Decorator Pattern</strong> to extend behavior while keeping the original code untouched.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Tab bar</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/34.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🔶 How matchedGeometryEffect() came to the rescue 🦸‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue33</link>
            <guid>33</guid>
            <pubDate>Mon, 17 Feb 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I chose to highlight the matchedGeometryEffect() modifier because it is a great tool for creating smooth, custom transitions between views — perfect even if you are not confident with animations!]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #33</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>At a previous sprint at work, I had faced a quite <strong>interesting challenge</strong> where I had to create an <strong>animated transition</strong> when selecting items from a grid.
The goal was to smoothly move the selected item within the grid.</p>
<p>Initially, I experimented with various <code>withAnimation</code> options but couldn't achieve the desired effect ... until I tried out using <strong>SwiftUI's</strong> <a href="https://developer.apple.com/documentation/swiftui/view/matchedgeometryeffect(id:in:properties:anchor:issource:)">matchedGeometryEffect()</a> modifier 🎉!</p>
<h3>Overview</h3>
<p>This week, I chose to highlight the <code>matchedGeometryEffect()</code> modifier because it is a great tool for creating <strong>smooth, custom transitions</strong> between <strong>views</strong> — perfect even if you are not confident with animations!</p>
<p>Using <strong>unique identifiers</strong>, you can blend the geometry of two views with the same identifier creating an animated transition.
Transitions like this can be useful for navigation or changing the state of UI elements for example.</p>
<h3>Steps to enable the Matched Geometry Effect:</h3>
<ul>
<li>Assign a <strong>unique identifier</strong> to each view involved in the transition.</li>
<li>Declare a namespace using the <code>@Namespace</code> property wrapper to group view identifiers.</li>
<li>Apply the <code>.matchedGeometryEffect(id:in:properties:anchor:isSource:)</code> modifier to the views participating in the animation.</li>
</ul>
<p>Once set up, when the animation is triggered, views with the same identifier within the same namespace will seamlessly transition between their states.</p>
<h3>My Coffees App</h3>
<p>I have assembled a <strong>practical example</strong> to demonstrate the advantages of using this <strong>view modifier</strong>.
Let's imagine you have an <strong>app</strong> that displays a grid of different types of <strong>coffee</strong> ☕ and you want to choose your <strong>favorites</strong> from that list - moving the selected ones from the one grid to the other with a smooth animation!</p>
<p>Here is a preview of what I am aiming for:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue33/coffees_animation.gif&quot;
alt=&quot;Coffee selection animation with the matchedGeometryEffect modifier.&quot;
link=&quot;/issues/issue33/coffees_animation.gif&quot;
caption=&quot;Coffee selection animation with the matchedGeometryEffect modifier.&quot;
priority={true}
/&gt;</p>
<p>Here is the code:</p>
<pre><code class="language-swift">struct MyCoffeesView: View {
    [...]

    @Namespace private var namespace
    private let coffeesNamespace = &quot;coffeesNamespace&quot;

    var body: some View {
        ScrollView {
            VStack {
                HeaderView(title: &quot;Favorites&quot;)

                LazyVGrid(columns: columns) {
                    if favoriteCoffees.isEmpty {
                        CoffeePlaceholderView()
                    } else {
                        ForEach(favoriteCoffees) { coffee in
                            CoffeeView(coffee: coffee)
                                .matchedGeometryEffect(
                                    id: &quot;\(coffee.name)_\(coffeesNamespace)&quot;, in: namespace
                                )
                                .onTapGesture {
                                    withAnimation(.easeIn) {
                                        favoriteCoffees.removeAll { $0.id == coffee.id }
                                    }
                                }
                        }
                    }
                }

                HeaderView(title: &quot;Suggested&quot;)

                LazyVGrid(columns: columns) {
                    if filteredSuggestedCoffees.isEmpty {
                        CoffeePlaceholderView()
                    } else {
                        ForEach(filteredSuggestedCoffees) { coffee in
                            CoffeeView(coffee: coffee)
                                .matchedGeometryEffect(
                                    id: &quot;\(coffee.name)_\(coffeesNamespace)&quot;, in: namespace
                                )
                                .onTapGesture {
                                    withAnimation(.easeIn) {
                                        favoriteCoffees.append(coffee)
                                    }
                                }
                        }
                    }
                }
            }
            .padding(.all)
        }
        .navigationBarTitle(&quot;My Coffees&quot;, displayMode: .inline)
    }
}
</code></pre>
<blockquote>
<p>To explore the full implementation of the sample application, visit the <a href="https://github.com/henriquestiagoo/matched-geometry-effect-demo">repository on GitHub</a>.</p>
</blockquote>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://swifttoolkit.dev/posts/LB-tree-1">🌳 Let's Build: The tree Program - Part I</a></h2>
<p><a href="https://x.com/SwiftToolkit">SwiftToolkit</a> is launching a new series called <strong>Let's Build</strong>!</p>
<p>In the <strong>first</strong> article of the series, you will explore file <strong>system traversal</strong> while building a directory listing tool.
This guide will walk you through using <strong>PathKit</strong> and the <strong>Swift Argument Parser</strong> to efficiently navigate and display directory structures.</p>
<h2><a href="https://swiftwithmajid.com/2025/02/11/task-cancellation-in-swift-concurrency/">⛔️ Task Cancellation in Swift Concurrency</a></h2>
<p>In most cases, <strong>Swift Concurrency</strong> automatically manages <strong>task cancellation</strong>, but there are situations where manual handling is necessary.</p>
<p><a href="https://x.com/mecid">Majid's</a> latest article explores Swift's <strong>cooperative cancellation</strong> model, explaining how developers can take control of <strong>task cancellation</strong> and decide when and how to stop execution!</p>
<h2><a href="https://serialcoder.dev/text-tutorials/swiftui/presenting-and-managing-expandable-sections-in-swiftui/">👷🏻‍♂️ Presenting and Managing Expandable Sections in SwiftUI</a></h2>
<p><strong>Expanding</strong> and <strong>collapsing</strong> views is essential for improving user experience.
This is particularly useful when deciding which information to display in limited space.</p>
<p><a href="https://x.com/gabtheodor">SerialCoder's</a> latest article covers how to manage the expanded state programmatically and how to let users expand and collapse sections on demand - all done in <strong>SwiftUI</strong>!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>SwiftUI</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/33.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🎓 How to Write Better Pull Requests ✍️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue32</link>
            <guid>32</guid>
            <pubDate>Sun, 09 Feb 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[Who doesn't love code reviews, right? I will be sharing some valuable tips to help you improve the way you create Pull Requests and make the review process smoother and more effective.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #32</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Who doesn't love <strong>code reviews</strong>, right? 😅
Recently, I watched <a href="https://x.com/dvrzan">Daniela Vrzan's</a> talk, <a href="https://vimeo.com/showcase/11503067/video/1011641324">Best-in-class Pull Request</a> from <a href="https://x.com/NSSpain">NSSpain</a> <strong>2024</strong>, and it gave me the inspiration for this week's issue.
I will be sharing some valuable <strong>tips</strong> to help you improve the way you create <strong>Pull Requests</strong> and make the review process smoother and more effective.</p>
<h3>What is a Pull Request? 🤔</h3>
<p>A <strong>pull request</strong> is a way to propose merging a set of changes from one branch into another.
It enables team members to <strong>review</strong>, <strong>discuss</strong> and <strong>provide feedback</strong> before the updates are incorporated into the <strong>main</strong> codebase.</p>
<h3>Tips to Write better PRs:</h3>
<ul>
<li>Don't do big PRs</li>
<li>Concise (write good descriptions)</li>
<li>Visual (screenshots/video)</li>
<li>Understandable and well-documented</li>
<li>Review your own pull request first</li>
<li>Avoid nitpicking!</li>
</ul>
<h3>Why and How to Add a PR Template?</h3>
<p>By having consistent prompts pre-filled in your description, you will always have a clear structure to follow, ensuring that your reviewers receive all the necessary details efficiently.</p>
<ul>
<li>Create a <code>.github</code> directory at the root of your repository</li>
<li>Inside it, add a file named <code>pull_request_template.md</code></li>
<li>Use <a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet">GitHub's Markdown syntax</a> to include prompts or guidelines that can help contributors provide useful information</li>
</ul>
<p>From now on, whenever you create a <strong>PR</strong>, the description field will automatically include your template content! Great Job! 💪</p>
<h3>What Should Your Template Include?</h3>
<p>You can add any prompts that suit your workflow.
Personally, I like to keep it straightforward.
Here is an example of a template:</p>
<pre><code># Problem Overview
- Brief description on what this PR is about
- Attach screenshots or anything valuable to the reviewer to give them context about your PR

# How To Test
- Step 1 
- Step 2 
- Step 3 

# Before And After
|            Before           |               After            |
|             :---:           |               :---:            |    
|       &lt;screenshot here&gt;     |        &lt;screenshot here&gt;       |

# Problem Solution
- Describe key changes 

## Issue
- [Jira task](&lt;link&gt;)

## How does this PR make you feel? (optional)
- [Gif](&lt;link&gt;)
</code></pre>
<p>Hopefully, these simple tips will help you turn each <strong>pull request</strong> into something special, making the <strong>review process</strong> more <strong>efficient</strong> and <strong>enjoyable</strong> for both you and your team 🤘!</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.artemnovichkov.com/blog/drawing-maps-with-swift-charts">🗺️ Drawing maps with Swift Charts</a></h2>
<p><a href="https://x.com/iosartem">Artem</a> got inspired by a <strong>Swift Charts</strong> WWDC session and decided to create an application to visualize population data of Kazakhstan 🇰🇿, the country where he resides.</p>
<p>If you are interested in learning how to create maps using <strong>Swift Charts</strong>, this article is definitely worth a read!</p>
<h2><a href="https://nowham.dev/posts/custom-actions/">✌️ Custom Fastlane Actions</a></h2>
<p>While <strong>Fastlane</strong> offers many built-in actions, there are times when you need a custom solution tailored to your workflow.</p>
<p>In his latest article, <a href="https://x.com/No_Wham">Noam</a> explains how to create <strong>custom Fastlane actions</strong> and also dives into <strong>unit testing</strong> your <strong>Fastlane</strong> code!</p>
<h2><a href="https://codingwithvera.com/what-the-is-a-copyable-2/">✂️ Swift 5.9: Copyable Syntax</a></h2>
<p>What exactly is a <strong>Copyable</strong>?</p>
<p>In her latest article, <a href="https://x.com/CodingWithVera">Vera</a> explores the concept of <strong>noncopyable</strong> structs and enums, a topic that has been gaining traction recently.
This new <strong>Swift 5.9</strong> feature improves code safety by preventing unintended copying of certain types.</p>
<p>If you are curious to learn more, <strong>Vera</strong> has put together a clear and insightful article where she shares her findings!</p>
<h2><a href="https://swiftwithmajid.com/2025/02/04/mastering-task-groups-in-swift/">🦑 Mastering TaskGroups in Swift</a></h2>
<p><strong>Swift Structured Concurrency</strong> simplifies handling multiple <strong>asynchronous</strong> tasks with <strong>task group</strong>.
These allow you to run a dynamic number of child tasks, wait for all to complete or cancel them if needed.</p>
<p><a href="https://x.com/mecid">Majid's</a> latest article dives into how to effectively use and optimize <strong>task groups</strong> in <strong>Swift</strong>.
It includes several practical code examples to illustrate their implementation, making it a great resource for improving your <strong>concurrency</strong> skills!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Pull Requests</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/32.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🎩 Using ImageRenderer in SwiftUI 🎨]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue31</link>
            <guid>31</guid>
            <pubDate>Mon, 03 Feb 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[ImageRenderer is a straightforward tool that can convert a SwiftUI view into various image formats such as CGImage, NSImage or UIImage. Using it is easy — just create an instance, give it some content and request an image output.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #31</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>When I first started posting on <strong>Twitter</strong>, I wasn't happy with how my newsletter posts displayed, so I built an automated system using <strong>SwiftUI</strong> and <strong>GitHub Actions</strong> to generate <strong>dynamic preview images</strong> for my weekly issues.
This approach <strong>saves time</strong> and ensures each post has a <strong>unique</strong>, <strong>professional look</strong> when shared online.</p>
<blockquote>
<p>This automated system is out the scope of this week's issue, but if you are curious on how I did it, I recommend checking out the <a href="https://www.tiagohenriques.dev/blog/generate-issue-preview-images-with-swiftui-and-github-actions">article</a> I wrote on this topic. It walks you through the entire process step by step!</p>
</blockquote>
<p>This week, I am diving into the <strong>key class</strong> that made it all possible 🎉 — <a href="https://developer.apple.com/documentation/swiftui/imagerenderer">ImageRenderer</a>.
I will show you how it works and how you can easily integrate it into your apps!</p>
<h3>Overview</h3>
<p><a href="https://developer.apple.com/documentation/swiftui/imagerenderer">ImageRenderer</a> is a straightforward tool that can convert a <strong>SwiftUI</strong> view into various image formats such as <strong>CGImage</strong>, <strong>NSImage</strong> or <strong>UIImage</strong>.</p>
<p>Using it is easy — just create an instance, <strong>give it</strong> some <strong>content</strong> and <strong>request</strong> an <strong>image output</strong>.</p>
<pre><code class="language-swift">let renderer = ImageRenderer(content: view)
self.image = renderer.uiImage
</code></pre>
<p>To see how the <strong>renderer</strong> works in a working example, here I am creating an <strong>image preview</strong> for my weekly issues given some properties such as the issue <strong>title</strong> and <strong>number</strong>.</p>
<pre><code class="language-swift">@main
struct IssuePreview: AsyncParsableCommand {
    [...]

    @MainActor mutating func run() async throws {
        [...]

        let view = IssueView(
            colors: colors,
            foregroundColor: foreground,
            title: issue.title,
            date: date,
            issueNumber: issue.number
        )
        .frame(width: 1280, height: 640)

        guard let image = ImageRenderer(content: view).nsImage else { throw Error.invalidImageData }
        guard let imageData = image.asPNGData else { throw Error.imageCreationFailed }

        let folderURL = URL(fileURLWithPath: &quot;issues&quot;)
        let fileURL = folderURL.appendingPathComponent(&quot;\(issue.number).png&quot;)
        try imageData.write(to: fileURL)
    }
}
</code></pre>
<h3>The Output</h3>
<p>Although I am (still considering) to make some adjustments and improvements, here is what I have got so far:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/main/issues/15.png&quot;
alt=&quot;iOS Coffee Break Newsletter issue #15 with custom image preview!&quot;
link=&quot;https://x.com/twannl/status/1669629139609944064&quot;
caption=&quot;iOS Coffee Break Newsletter issue #15 with custom preview image!&quot;
/&gt;</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://www.darrylbayliss.net/multiplatform-development-for-apple-devices/">🍎📱💻 Multiplatform Development for Apple Devices</a></h2>
<p>Are you working to make your app <strong>run</strong> across <strong>multiple Apple platforms</strong>?</p>
<p>In his first blog post of 2025, <a href="https://x.com/darryl_bayliss">Darryl</a> walks through the process of bringing his side project to the <strong>Vision Pro</strong>.
If you are working on making your own apps compatible with new <strong>Apple</strong> devices, this is definitely worth a read!</p>
<h2><a href="https://swiftwithmajid.com/2025/01/28/container-relative-frames-in-swiftui/">🦺 Container relative frames in SwiftUI</a></h2>
<p>If you have encountered performance issues from overusing <strong>GeometryReader</strong> in your <strong>SwiftUI</strong> apps, you might want to check out <a href="https://x.com/mecid">Majid's</a> article!</p>
<p>He explains how to use the <code>containerRelativeFrame</code> view modifier, which allows you to define a view’s size relative to its parent without relying on <strong>GeometryReader</strong>.
This can help simplify your layouts and improve performance.</p>
<h2><a href="https://swifttoolkit.dev/posts/dc-krzysztof">🎙️ Dev Conversations #6: Krzysztof Zabłocki</a></h2>
<p><a href="https://swifttoolkit.dev/posts/categories/dev-conversations">Dev Conversations</a> is a monthly series where <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> features people who contribute to the <strong>Swift</strong> community!</p>
<p>In episode #6, <a href="https://x.com/natanrolnik">Natan</a> interviews <a href="https://x.com/merowing_">Krzysztof</a>, the creator of <a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a>, to discuss his career, open-source contributions, and his decision to leave a full-time job to become independent.
It is a great talk that might just inspire you to go full indie 🚀!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>SwiftUI</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/31.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Part 3 of Bringing App Intents to Your SwiftUI App 🍭]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue30</link>
            <guid>30</guid>
            <pubDate>Mon, 27 Jan 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, we reach the 3rd and final part of the series on App Intents! This time, I will continue refining my to-dos sample app and show you how you can create interactive widgets using App Intents.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #30</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬!</p>
<p>In last week <a href="https://www.ioscoffeebreak.com/issue/issue29">issue</a> and <strong>part 2</strong> of the series on <strong>App Intents</strong>, I showed you how to take advantage of <strong>App Intents</strong> and take the <strong>to-dos</strong> working sample app to the next level by using the <a href="https://developer.apple.com/documentation/appintents/showssnippetview">ShowsSnippetView</a> protocol to return a custom view as a result of performing an action.</p>
<blockquote>
<p>In case you missed the previous issues, you can check out part 1 <a href="https://www.ioscoffeebreak.com/issue/issue28">here</a> and part 2 <a href="https://www.ioscoffeebreak.com/issue/issue29">here</a>.</p>
</blockquote>
<p>Tired of <strong>App Intents</strong> already? We are not over yet 😅 ...</p>
<p>This week, we reach the <strong>3rd</strong> and <strong>final</strong> part of the series on <strong>App Intents</strong>!
This time, I will continue refining my <strong>to-dos</strong> sample app and show you how you can create <strong>interactive widgets</strong> 🕹 using <strong>App Intents</strong>.</p>
<h2>The Plan</h2>
<ul>
<li>Create a widget that displays the top three to-do items.</li>
<li>Enable users to mark a to-do as completed directly from the widget.</li>
</ul>
<blockquote>
<p>I have written a detailed guide on the topic <a href="https://www.tiagohenriques.dev/blog/interactive-widgets-using-app-intents">here</a>. If you are interested in diving deeper into the implementation details,I highly recommend giving it a read!</p>
</blockquote>
<p>Here is the final result:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue30/mark_todo_completed_widget.gif&quot;
alt=&quot;Marking a to-do as completed using the widget.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue30/mark_todo_completed_widget.gif&quot;
caption=&quot;Marking a to-do as completed using the widget.&quot;
priority={true}
/&gt;</p>
<blockquote>
<p>To explore the full implementation of the sample application, visit the <a href="https://github.com/henriquestiagoo/my-todos/tree/widgets">My To-dos app repository on GitHub</a>.</p>
</blockquote>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://swifttoolkit.dev/posts/mustache-analytics">🥸 Generating Analytics Code with Mustache</a></h2>
<p>Ever wondered how to build a <strong>CLI</strong> tool that generates code?</p>
<p>This week, <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> shared an detailed guide on generating analytics events from markdown tables using <strong>Mustache</strong> templates, transforming them into <strong>Swift</strong> or <strong>Kotlin</strong> code.</p>
<h2><a href="https://swiftandmemes.com/how-to-build-a-dream-team-a-guide-to-recruiting-great-mobile-developers/">🏆 How to Build a Dream Team: A Guide to Recruiting Great Mobile Developers</a></h2>
<p>Finding and recruiting exceptional developers who align with your culture is hard!
<a href="https://x.com/PawelKozielecki">Pawel</a> has put together a valuable guide sharing his insights on what truly counts when assembling high-performing <strong>iOS</strong> development teams.</p>
<p>If you are currently applying for new positions or even if your team is hiring, this article might be of great value for you.</p>
<h2><a href="https://peterfriese.dev/blog/2025/swiftui-action-menu/">🧩 Creating a reusable action menu component in SwiftUI</a></h2>
<p>At some point in your development journey, I bet you've likely encountered code that feels repetitive, overly dependent on the app's data model, and lacking in structure.</p>
<p>In his latest article, <a href="https://x.com/peterfriese">Peter</a> walks you through the process of building a <strong>reusable SwiftUI component</strong>, helping you write cleaner and more maintainable code!</p>
<h2><a href="https://codingwithvera.com/swift-11-protocols/">📜 Swift 1:1: Protocols</a></h2>
<p>Regardless of the programming language — be it <strong>Swift</strong>, <strong>Kotlin</strong>, or <strong>C#</strong> — <strong>protocols (or interfaces)</strong> provide an effective way to handle data flow between objects.</p>
<p>In her latest article, <a href="https://x.com/CodingWithVera">Vera</a> breaks down <strong>Swift</strong> protocols in an easy-to-understand manner, making it accessible for developers at all levels.</p>
<h2><a href="https://nowham.dev/posts/swiftformat-on-ci/">🤖 Running SwiftFormat on CI</a></h2>
<p>If you or your team run workflows on any <strong>CI</strong> platform, you know that getting them to work in that <strong>environment</strong> is a different story from running them <strong>locally</strong>!</p>
<p><a href="https://x.com/No_Wham">Noam</a> has written an insightful guide on how to create a script that runs <a href="https://github.com/nicklockwood/SwiftFormat">SwiftFormat</a>, detects any file changes, and commits them automatically — all set up to work seamlessly within your <strong>CI</strong> pipeline.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>App Intents</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/30.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Part 2 of Bringing App Intents to Your SwiftUI App 🍭]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue29</link>
            <guid>29</guid>
            <pubDate>Mon, 20 Jan 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I will show how you can take App Intents to the next level by taking advantage of the ShowsSnippetView protocol to return a custom view as a result of performing an action.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #29</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and the <strong>second</strong> edition of <strong>2025</strong>.</p>
<p>Last week <a href="https://www.ioscoffeebreak.com/issue/issue28">issue</a> discussed the advantages and implementation details of the <strong>App Intents</strong> and the <strong>App Shortcuts</strong> frameworks in <strong>iOS</strong>, using a <strong>to-dos</strong> sample application as a working example.</p>
<blockquote>
<p>In case you missed the previous issue, you can check it out <a href="https://www.ioscoffeebreak.com/issue/issue28">here</a>.</p>
</blockquote>
<p>Do you recall the boring dialog that gets displayed when our todo is marked as completed? What if there is a way to improve it 🤔 ...</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue29/mark_resolved_intent_with_dialog.gif&quot;
alt=&quot;My To-Do App Intents demo with Dialog.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue29/mark_resolved_intent_with_dialog.gif&quot;
caption=&quot;My To-Do App Intents demo with Dialog.&quot;
priority={true}
/&gt;</p>
<p>This week, I will show how you can take <strong>App Intents</strong> to the next level by taking advantage of the <a href="https://developer.apple.com/documentation/appintents/showssnippetview">ShowsSnippetView</a> protocol to return a custom view as a result of performing an action.</p>
<h2>Jumping to the Code</h2>
<p>First, lets create our view.
Here is how the custom <code>TodoActionView</code> looks:</p>
<pre><code class="language-swift">import SwiftUI

struct TodoActionView: View {
    let action: TodoAction
    let title: String

    var body: some View {
        HStack {
            Image(systemName: action.imageName)
                .imageScale(.large)
                .font(.largeTitle)
            Text(&quot;'\(title)' \(action.name).&quot;)
                .font(.title2)
        }
        .padding()
    }
}
</code></pre>
<p>To display a view when marking a <strong>to-do</strong> as completed, update the <code>perform</code> method's return type to include <code>ShowsSnippetView</code>.
Then, use the result method to pass <code>TodoActionView</code> as a parameter.</p>
<p>Here is how the code looks:</p>
<pre><code class="language-swift">import AppIntents
import SwiftUI

struct MarkTodoAsCompletedIntent: AppIntent {
    [...]

    func perform() async throws -&gt; some ShowsSnippetView {
        let suggestedEntities = try await suggestedEntities()
        if suggestedEntities.isEmpty {
            return await .result(view: TodosEmptyView())
        } else {
            let entityToUpdate = try await $titleEntity.requestDisambiguation(
                among: suggestedEntities,
                dialog: IntentDialog(&quot;Select the todo you wish to mark as completed:&quot;)
            )
            // mark todo as completed
            try await markAsCompleted(title: entityToUpdate.id)
            return .result(view: TodoActionView(action: .markAsComplete, title: entityToUpdate.id))
        }
    }

    [...]
}
</code></pre>
<p>With that simple adjustment, the <strong>App Intent</strong> action delivers a custom and more engaging view.
Here is how the demo of the sample <strong>to-dos</strong> application now behaves:</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue29/mark_resolved_intent_with_view.gif&quot;
alt=&quot;My To-Do App Intents demo with custom view.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue29/mark_resolved_intent_with_view.gif&quot;
caption=&quot;My To-Do App Intents demo with custom view.&quot;
priority={true}
/&gt;</p>
<p>For those interested in diving deeper into this topic, consider experimenting with various types of intents to see how they can be customized to meet your app's specific needs.</p>
<blockquote>
<p>If you are considering adding <strong>App Intents</strong> to your app, make sure to review the <a href="https://developer.apple.com/design/human-interface-guidelines/app-shortcuts/">Human Interface Guidelines</a>.
They provide valuable insights into what types of actions are suitable for <strong>App Intents</strong>, ensuring they align with best practices and offer an intuitive user experience.</p>
</blockquote>
<p>I am planning to release a <strong>3rd</strong> part of my <strong>App Intents</strong> issues by powering up my <strong>to-do</strong> sample application with <strong>interactive widgets</strong>! Stay tunned!</p>
<p>To explore the full implementation of the sample application, visit the <a href="https://github.com/henriquestiagoo/my-todos/tree/shows-snippet-view">to-dos app repository on GitHub</a>.</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://nowham.dev/posts/xcode_shortcuts/">🤘 Favorite Xcode shortcuts</a></h2>
<p><strong>Xcode</strong> offers countless shortcuts, and I am sure everyone has their go-to favorites.
In his latest article, <a href="https://x.com/No_Wham">Nowham</a> highlights the most useful shortcuts he relies on daily.
It is a must-read for improving efficiency!</p>
<p>If you are like me and keep mistyping variables names all the time, the <strong>Edit all in scope</strong> shortcut comes pretty handy!</p>
<h2><a href="https://swifttoolkit.dev/posts/clis-rambo">🔨 Swift Argument Parser with Guilherme Rambo</a></h2>
<p><a href="https://x.com/SwiftToolkit">Swift Toolkit</a> has released an insightful video featuring <a href="https://x.com/natanrolnik">Natan</a> and <a href="https://x.com/_inside">Gui Rambo</a>, where they delve into <strong>Command Line</strong> tools in <strong>Swift</strong>.
They showcase a practical refactor and demonstrate integrating <strong>CLI</strong> functionality into <strong>macOS</strong> apps.</p>
<p>If you are passionate about tooling and server side in <strong>Swift</strong>, <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> is the right place for you.</p>
<h2><a href="https://blog.thomasdurand.fr/story/2025-01-17-attending-apple-workshop/#fnref:3">🧑‍💻 Attending Apple Intelligence and App Intents workshop</a></h2>
<p>While researching for my latest issue, I came across <a href="https://blog.thomasdurand.fr/">Dean's blog</a> and his insightful article on <strong>Apple Intents</strong>.
<a href="https://x.com/deanatoire">Dean</a> recently attended an <strong>Apple Intelligence</strong> and <strong>App Intents</strong> workshop in Paris, led by an <strong>Apple</strong> expert, and shared his experience in detail.</p>
<p>It is exciting to see <strong>Apple</strong> hosting such local events worldwide.
I would be thrilled to have the chance to participate in one someday!</p>
<h2><a href="https://www.swiftwithvincent.com/blog/introduction-to-non-copyable-types">✂️ Introduction to Non-Copyable types in Swift</a></h2>
<p>Have you come across <strong>non-copyable</strong> types in <strong>Swift</strong>? I hadn't until recently!</p>
<p>This new feature, recently introduced to <strong>Swift</strong>, enhances code safety by preventing unintended copying of certain types.
If you are curious to learn more, <a href="https://x.com/v_pradeilles">Vincent</a> has created a straightforward video explaining the concept and its practical applications.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>App Intents</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/29.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[✅ Bringing App Intents to Your SwiftUI App 🍭]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue28</link>
            <guid>28</guid>
            <pubDate>Mon, 13 Jan 2025 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I wrote an article that discusses the advantages and implementation details of the App Intents and the App Shortcuts frameworks in iOS, using a To-dos sample application as a working example to demonstrate how they can make user interactions easier and more intuitive.]]></description>
            <content:encoded><![CDATA[<p>Welcome to <strong>issue #28</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬 and the <strong>first</strong> edition of <strong>2025</strong>.
I hope you had a lovely start of the year 🥳!</p>
<p>This week I wrote an <a href="https://www.tiagohenriques.dev/blog/bringing-app-intents-to-your-swiftui-app">article</a> that discusses the advantages and implementation details of the <a href="https://developer.apple.com/documentation/appintents">App Intents</a> and the <a href="https://developer.apple.com/documentation/appintents/app-shortcuts">App Shortcuts</a> frameworks in <strong>iOS</strong>, using a <strong>To-dos</strong> sample application as a working example to demonstrate how they can make user interactions easier and more intuitive.</p>
<blockquote>
<p>The App Intents framework enables seamless integration of your app's features with system experiences like <strong>Siri</strong>, <strong>Spotlight</strong> and <strong>Shortcuts</strong>.
Enhanced by <strong>Apple Intelligence</strong>, it boosts discoverability and personalization by suggesting actions and enabling interactions across apps.</p>
</blockquote>
<p>For this example, we are interested in the following actions:</p>
<ul>
<li>Show the list of tasks</li>
<li>Add a new task</li>
<li>Remove a task</li>
<li>Mark a task as completed</li>
</ul>
<h2>Defining App Intents</h2>
<p>To define <strong>App Intents</strong>, just add a new file to your main app target and create a struct that conforms to the <a href="https://developer.apple.com/documentation/appintents/appintent">AppIntent</a> protocol.
The system will automatically discover any intents defined by your app and will show them accordingly where appropriate.</p>
<p>We will take as example the <strong>add to-do</strong> intent that looks as follows:</p>
<pre><code class="language-swift">import AppIntents

/// Add to-do App Intent
struct AddTodoIntent: AppIntent {
    static var title: LocalizedStringResource = LocalizedStringResource(stringLiteral: &quot;Add item to todos list&quot;)
    static var description: IntentDescription? = IntentDescription(stringLiteral: &quot;Add an item to todos list&quot;)

    @Parameter(title: &quot;Todo title&quot;)
    var todoTitle: String?

    func perform() async throws -&gt; some ProvidesDialog {
        guard let todoTitle else {
            let dialog = IntentDialog(&quot;What todo item you would like to add?&quot;)
            throw $todoTitle.needsValueError(dialog)
        }

        let newTodo = Todo(title: todoTitle)
        do {
            try await insert(todo: newTodo)
            let dialog = IntentDialog(&quot;'\(todoTitle)' was added to your todos list.&quot;)
            return .result(dialog: dialog)
        } catch {
            throw error
        }
    }

    @MainActor
    func insert(todo: Todo) async throws {
        let todosManager = TodosManager(context: MyTodosApp.container.mainContext)
        try await todosManager.insert(todo: todo)
    }
}
</code></pre>
<h2>Making your Intents accessible through Shortcuts</h2>
<p>A great feature of Intents is their ability to appear in multiple system locations.
To ensure actions are accessible via <strong>Spotlight</strong>, you need to implement an <a href="https://developer.apple.com/documentation/appintents/appshortcutsprovider">AppShortcutsProvider</a> instance.</p>
<pre><code class="language-swift">import AppIntents

struct MyTodosShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: AddTodoIntent(),
            phrases: [
                &quot;Add an item to \(.applicationName)&quot;,
                &quot;Add item to \(.applicationName)&quot;,
            ],
            shortTitle: LocalizedStringResource(stringLiteral: &quot;Add an item to todos list&quot;),
            systemImageName: &quot;plus.circle.fill&quot;
        )
    }
}
</code></pre>
<p>With this setup, your app's functionality becomes fully accessible as a <strong>Shortcut</strong>.</p>
<p>Here is a demo of the sample <strong>to-dos</strong> application using <strong>App Intents</strong>.</p>
<p>&lt;StaticHalfWidthImage
src=&quot;/issues/issue28/addtodo.gif&quot;
alt=&quot;My To-Do App Intents demo.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue28/addtodo.gif&quot;
caption=&quot;My To-Do App Intents demo.&quot;
priority={true}
/&gt;</p>
<p>App Intents can also power <strong>interactive widgets</strong>, <strong>controls</strong> and <strong>live activities</strong>, which I plan to explore in future issues!</p>
<p>To explore the full implementation of the sample application and to get more details of how <strong>App Intents</strong> and <strong>App Shortcuts</strong> frameworks work, visit my latest <a href="https://www.tiagohenriques.dev/blog/bringing-app-intents-to-your-swiftui-app">article</a> on my blog.</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<p>&lt;Banner text=&quot;CURATED FROM THE COMMUNITY&quot; /&gt;</p>
<h2><a href="https://danielsaidi.com/blog/2025/01/04/creating-tiny-utility-apps-with-swiftui-previews">🪚 Creating tiny utility apps with SwiftUI Previews</a></h2>
<p>In this post, <a href="https://x.com/danielsaidi">Daniel</a> demonstrates how to create lightweight apps without needing to install them on a device by leveraging <strong>SwiftUI Previews</strong> and <strong>Swift Package</strong> internal views.
Thanks to <strong>SwiftUI</strong>, which simplifies development compared to <strong>UIKit</strong> and <strong>AppKit</strong>, you can build cross-platform apps efficiently.</p>
<p>Personally, I believe this method serves as an excellent alternative to standalone apps, streamlining the development process and saving time to focus on other priorities 👌.</p>
<h2><a href="https://blog.makwanbk.com/how-one-new-xcode-feature-helped-my-work-project-eliminate-66k-lines-of-code">🪥 How a new Xcode 16 feature helped my work project eliminate 66,000 lines of code</a></h2>
<p><strong>Xcode 16's</strong> new buildable folders don't depend on <code>.pbxproj</code> for recognising files, which helps teams avoid possible merge conflicts with file changes in their git branches.
This feature allowed <a href="https://x.com/makwanbk">Makwan's</a> team to find over <code>100</code> unused <strong>Swift</strong> files and eliminate a total of <code>66,000</code> lines of code.</p>
<p>I suggest reading this article for a deeper understanding of how the author and the team tackled this time-consumig process.
It might inspire you to clean up some of your project's files as well!</p>
<h2><a href="https://codingwithvera.com/swift-6-typed-throws/">🪝 Swift 6: Typed Throws</a></h2>
<p><strong>Swift 6</strong> introduces many exciting features, including <strong>Typed Throws</strong>, which improve the way we handle errors.</p>
<p>In her latest blog post, <a href="https://x.com/CodingWithVera">Vera</a> explains how specifying <strong>error types</strong> allows the compiler to detect issues more appropriately.</p>
<h2><a href="https://tuist.dev/blog/2024/12/31/signing-macos-clis">🖊️ The ultimate guide to signing CLIs for macOS (Darwin)</a></h2>
<p>Did you ever get the error <code>&quot;'your-cli' can't be opened because Apple cannot check it for malicious software.&quot;</code> after installing a <strong>macOS CLI</strong> tool? I bet you did - this happens because <strong>macOS</strong> has a security feature called <strong>Gatekeeper</strong>, which is designed to ensure that only trusted software runs on the system.</p>
<p><a href="https://x.com/pepicrft">Pedro</a> from <a href="https://x.com/tuistdev">Tuist</a> has written a comprehensive guide on <strong>signing</strong> and <strong>notarizing</strong> your <strong>CLI</strong> tool for <strong>macOS</strong> to resolve this issue effectively!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>App Intents</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/28.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🫣 2024 wrapped 🥁]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue27</link>
            <guid>27</guid>
            <pubDate>Mon, 30 Dec 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[As the year comes to an end, what a journey it has been! I am incredibly proud of everything I have created in 2024, so here is a quick look back at some highlights from your favorite iOS newsletter.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #27</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>As the year comes to an end, what a journey it has been!
I am incredibly proud of everything I have created in <strong>2024</strong>!</p>
<p>I had two big concerns when I started the newsletter: not to be able to find or receive from the community enough <strong>iOS</strong> content to feature every month and not to have enough people interested in subscribing.
Those worries are now behind me! I now receive plenty of requests to showcase new articles and have transitioned to <strong>releasing issues weekly</strong>.
On top of that, we are close to <strong>500</strong> subscribers!</p>
<p>I am incredibly grateful to everyone who has supported the newsletter, whether by <strong>subscribing</strong> or <strong>contributing</strong> with such amazing content. Thank you all 🙏!</p>
<p>Here is a quick look back at some highlights from your favorite <strong>iOS</strong> newsletter ☕.</p>
<h2>Year Highlights</h2>
<p><strong>2024</strong> was a big year for the newsletter:</p>
<ul>
<li><strong>Launch</strong> of <strong>iOS Coffee Break</strong> in May 2024.</li>
<li><strong>7.6k</strong> unique visitors to the site.</li>
<li><strong>27</strong> issues published.</li>
<li><strong>Revamp</strong> of the site, including a dedicated page to <a href="https://www.ioscoffeebreak.com/sponsor">sponsorship</a> opportunities.</li>
</ul>
<p>Take a deeper dive with me into the most popular issues from the past year.</p>
<h2>Top Issues</h2>
<h3><a href="https://www.ioscoffeebreak.com/issue/issue25">🧰 The collection of open-source iOS tools I rely on daily ✌️</a></h3>
<p>This was one of my favorite issues to write, and it turned out to be the <strong>most read</strong> in the newsletter!
I showcased some <strong>open-source tools</strong> that I frequently use in both professional and personal <strong>iOS</strong> development.</p>
<h3><a href="https://www.ioscoffeebreak.com/issue/issue22">👷 Refactoring my SwiftUI Navigation Layer to follow the Coordinator Pattern 🔀</a></h3>
<p>The <strong>second most popular</strong> issue in the newsletter focused on refactoring my earlier <strong>SwiftUI Navigation Layer</strong>.
Here, I transitioned from a <strong>Router</strong> to a <strong>Coordinator</strong> model and the main goal of this refactoring was to transition from a linear navigation stack to a distinct set of independent navigation screens using sheet presentations.</p>
<p>I must say, this was the issue I dedicated the most time and effort to 😅!</p>
<h3><a href="https://www.ioscoffeebreak.com/issue/issue20">🧑‍✈️ GitHub Copilot for Xcode is now available! ✈️</a></h3>
<p>Rounding out the <strong>top three</strong> of my most viewed issues is the announcement of <strong>GitHub Copilot for Xcode</strong>!</p>
<p>With <strong>AI</strong> being such a hot topic in <strong>2024</strong>, it is no surprise this issue resonated with readers.
This <strong>Xcode</strong> extension offers inline code suggestions as you type, significantly boosting development efficiency.</p>
<h2>See you in 2025! 🥳</h2>
<p>I am deeply grateful to all my <strong>readers</strong> and <strong>subscribers</strong> for their unwavering support.
Your engagement inspires me to continue creating free, valuable content for the <strong>iOS</strong> community.
I couldn't do it without you — thank you 🙏</p>
<p>I wish you lots of <strong>coffees</strong> and I hope to see you in <strong>2025</strong> 🥳</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/27.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🎅 Bringing the Image Playground API to your SwiftUI App 🪄]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue26</link>
            <guid>26</guid>
            <pubDate>Mon, 23 Dec 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[One of the standout announcements at WWDC 2024 was the introduction of the Image Playground framework, a powerful image generator powered by an on-device diffusion model. This innovative tool offers advanced capabilities directly on Apple devices. ]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #26</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<blockquote>
<p>It is that time of year again — Merry Christmas, everyone 🎄🎅 Wishing you a joyful holiday season filled with rest, relaxation, cherished moments with your loved ones!</p>
</blockquote>
<p>One of the standout announcements at <strong>WWDC 2024</strong> was the introduction of the <a href="https://developer.apple.com/documentation/imageplayground">Image Playground</a> framework, a powerful image generator powered by an on-device diffusion model.
This innovative tool offers advanced capabilities directly on Apple devices.
The API for <strong>Image Playground</strong> is currently in beta and is compatible with iOS <strong>18.2</strong>, <strong>iPadOS 18.2</strong>, and <strong>macOS 15.2</strong> or later.</p>
<blockquote>
<p>To use the Image Playground app, ensure Apple Intelligence is enabled by navigating to System Settings &gt; Apple Intelligence &amp; Siri. In my case, I had to adjust the Apple Intelligence language to English (US) to match my system language. Only then did the option to toggle on Apple Intelligence become available.</p>
</blockquote>
<h3>Integration in a SwiftUI App</h3>
<p>The method <code>imagePlaygroundSheet(isPresented:concept:sourceImageURL:onCompletion:onCancellation:)</code> allows the presentation of the sheet where the user generates images from the specified inputs.
In <strong>SwiftUI</strong>, you present this interface as a sheet from one of your views:</p>
<pre><code class="language-swift">import ImagePlayground
import SwiftUI

struct ImagePlaygroundView: View {
    @State private var isImagePlaygroundPresented = false
    @State private var imageURL: URL?
    @Environment(\.supportsImagePlayground) private var supportsImagePlayground

    var body: some View {
        VStack {
            if let imageURL {
                AsyncImage(url: imageURL) { image in
                    image
                        .resizable()
                        .scaledToFit()
                        .frame(maxHeight: 300)
                } placeholder: {
                    ProgressView()
                }
            }

            if supportsImagePlayground {
                Button(&quot;Generate&quot;, systemImage: &quot;wand.and.sparkles&quot;) {
                    isImagePlaygroundPresented.toggle()
                }
            } else {
                Text(&quot;Image Playground is not supported on this device.&quot;)
                    .multilineTextAlignment(.center)
            }
        }
        .padding()
        .imagePlaygroundSheet(
            isPresented: $isImagePlaygroundPresented,
            concepts: [.text(&quot;cat&quot;), .text(&quot;astronaut&quot;)]
        ) { url in
            imageURL = url
        }
    }
}
</code></pre>
<blockquote>
<p>I was not able to run this code on an iOS simulator with Apple Intelligence enabled. If you have managed to make it work, please let me know on Twitter!.</p>
</blockquote>
<p>Here is the result of the sample code running on my mac:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue26/image_playground_output.webp&quot;
alt=&quot;Custom Optional output.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue26/image_playground_output.webp&quot;
caption=&quot;Output image from the sample code.&quot;
priority={true}
/&gt;</p>
<p>Apple's <strong>Image Playground</strong> allows developers to create visually engaging experiences while ensuring smooth integration with app frameworks.
Currently, the model just supports generating animations and illustrations, but my expectation is that future updates will expand its capabilities!</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://vimeo.com/showcase/11503067">☠️ NSSpain XII (2024) talks are available online!</a></h2>
<p><strong>NSSpain</strong> was one of the <strong>iOS</strong> conferences I eagerly anticipated attending this year, but unfortunately, I couldn't make it.</p>
<p>Thankfully, for those who missed out, the <strong>NSSpain</strong> team has generously uploaded all the talks from the 12th edition to Vimeo, making them accessible to everyone.
Consider it as a christmas gift! 🎄🎅</p>
<h2><a href="https://michaellong.medium.com/now-previewing-navigator-faebf290a1da">👀 Now Previewing Navigator!</a></h2>
<p>I have been a long-time follower of <a href="https://www.linkedin.com/in/hmlong/">Michael's</a> work and greatly admire his approach to Dependency Injection using the <a href="https://github.com/hmlongco/Factory">Factory</a> and <a href="https://github.com/hmlongco/Resolver">Resolver</a> libraries.
I even integrated Factory into <a href="https://apps.apple.com/us/app/padel-time/id6471981060">Padel Time</a>, my side project built entirely in <strong>SwiftUI</strong>, and it definitely made my life easier!</p>
<p><strong>Michael's</strong> latest project, <a href="https://github.com/hmlongco/Navigator">Navigator</a>, offers a streamlined yet robust navigation layer built around <code>NavigationStack</code>.
As it is still in its pre-release phase, this is an excellent opportunity to dive in, experiment, and provide feedback to shape its development!</p>
<h2><a href="https://touchlab.co/xcodekotlin">🧩 Xcode Kotlin - Xcode support for Kotlin browsing and debugging</a></h2>
<p>At work, we use a <strong>KMP</strong> module written in Kotlin that is shared between our <strong>iOS</strong> and <strong>android</strong> apps.
A recurring issue for the <strong>iOS</strong> team has been debugging the Kotlin code when unexpected behavior occurs.
So far, we have had to rely on less effective approaches like using print statements to identify problems.</p>
<p>Thankfully, <a href="https://x.com/TouchlabHQ">Touchlab's</a> new xcode-kotlin plugin directly integrates <strong>Kotlin</strong> debugging into <strong>Xcode</strong>. This tool simplifies troubleshooting shared code, and it is something I am excited to introduce to my team for improved efficiency!</p>
<h2><a href="https://swifttoolkit.dev/posts/swift-mustache">🥸 Templating with Mustache: an Interactive Tutorial</a></h2>
<p>When I discovered this post, I knew it had to be in this week's newsletter.
A few years ago, I worked on a <strong>tvOS</strong> project at work where we used a templating engine with <a href="https://github.com/janl/mustache.js">Mustache.js</a> to design <strong>TVML</strong> pages.
The engine injected data into templates at runtime to generate dynamic content for <strong>tvOS</strong>.</p>
<p><a href="https://x.com/natanrolnik">Natan's</a> latest article in <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> explores leveraging <strong>Mustache</strong> in <strong>Swift</strong> to create code, HTML, and dynamic content.
His guide offers a clear deep dive into its practical applications and it is definitely a great skill to have!</p>
<h2><a href="https://github.com/danielsaidi/SwiftPackageScripts">🚀 Swift Package Scripts 0.2 is out!</a></h2>
<p><a href="https://x.com/danielsaidi">Daniel Saidi</a> has launched version 0.2 of Swift Package Scripts!
This repository includes helpful shell scripts for tasks like building, testing, generating Docc documentation, and creating new versions.</p>
<p>With v0.2, you can specify platforms for execution, and it introduces a multi-platform compatible XCFramework script.
I will definitely apply some of these scripts into my workflows!</p>
<h2><a href="https://azamsharp.com/2024/12/18/the-ultimate-guide-to-validation-patterns-in-swiftui.html">🕵️‍♂️ The Ultimate Guide to Validation Patterns in SwiftUI</a></h2>
<p>Validation plays a crucial role in crafting reliable and user-friendly applications, and it doesn't need to be overly complex!</p>
<p><a href="https://x.com/azamsharp">Azam</a> has written a detailed guide showcasing techniques for implementing effective validation in <strong>SwiftUI</strong> apps, emphasizing strategies to improve both data integrity and the overall user experience.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>AI</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/26.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🧰 The collection of open-source iOS tools I rely on daily ✌️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue25</link>
            <guid>25</guid>
            <pubDate>Mon, 16 Dec 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[The iOS community has a very active open-source scene, which provides a lot of useful tools to improve the quality of an app. This week, I am highlighting some open-source utilities that I regularly use in both my professional and personal iOS development projects.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #25</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>The <strong>iOS</strong> community has a very active open-source scene, which provides a lot of useful tools to improve the quality of an app.
This week, I am highlighting some open-source utilities that I regularly use in both my professional and personal <strong>iOS</strong> development projects.</p>
<h3><a href="https://github.com/realm/SwiftLint">SwiftLint</a></h3>
<p><strong>SwiftLint</strong> enforces coding standards and best practices in <strong>Swift</strong>, promoting clean, maintainable, and readable code.
It flags issues like force-unwrapping through warnings and errors, similar to a code review.
By automating this process, <strong>SwiftLint</strong> reduces manual effort during reviews, enabling developers to focus on more critical aspects.</p>
<p>Here is an example of how you can disable rules in code:</p>
<pre><code class="language-swift">// swiftlint:disable colon
let noWarning :String = &quot;&quot; // No warning about colons immediately after variable names!
// swiftlint:enable colon
let hasWarning :String = &quot;&quot; // Warning generated about colons immediately after variable names.
</code></pre>
<blockquote>
<p>If you are not aware, you can install and run SwiftLint globally, allowing you to check the code quality of any file on your Mac.</p>
</blockquote>
<h3><a href="https://fastlane.tools/">Fastlane</a></h3>
<p><strong>Fastlane</strong> is a versatile automation tool designed for mobile app projects, offering a wide array of actions and plugins.
It allows you to create complex workflows, known as &quot;lanes&quot; to perform tasks such as building, testing or deploying your <strong>iOS</strong> application.
It integrates seamlessly with various <strong>CI</strong> services and uses a configuration file called a <code>Fastfile</code> to define these workflows.
This makes it a powerful solution for streamlining repetitive processes and maintaining efficiency in your app development pipeline.</p>
<p>Here is a sample <code>Fastfile</code> with a test lane:</p>
<pre><code class="language-bash">default_platform(:ios)

platform :ios do
  project_path = &quot;myProject/myProject.xcodeproj&quot;

  desc &quot;Run iOS tests&quot;
  lane :test do
    run_tests(
      project: project_path
    )
  end
end
</code></pre>
<h3><a href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a></h3>
<p><strong>SwiftGen</strong> is a tool that generates <strong>Swift</strong> code to provide type-safe access to project resources like images, localized strings, and more.
By automating this process, <strong>SwiftGen</strong> helps prevent runtime errors caused by incorrect resource usage, ensuring a safer and more efficient development workflow.</p>
<p>Here is an usage example:</p>
<pre><code class="language-swift">// You can create new images by referring to the enum instance and calling `.image` on it:
let bananaImage = Asset.Exotic.banana.image
let privateImage = Asset.private.image

// You can create colors by referring to the enum instance and calling `.color` on it:
let primaryColor = Asset.Styles.Vengo.primary.color
let tintColor = Asset.Styles.Vengo.tint.color

// You can create data items by referring to the enum instance and calling `.data` on it:
let data = Asset.data.data
let readme = Asset.readme.data
</code></pre>
<h3><a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a></h3>
<p>Created by <a href="https://x.com/merowing_">Krzysztof</a>, <strong>Sourcery</strong> is a <strong>Swift</strong> code generator built on top of <strong>SwiftSyntax</strong>.
It enhances language abstractions, enabling developers to automatically create boilerplate code.</p>
<p>Here is an example of how to use it with a <code>Struct</code>:</p>
<pre><code class="language-swift">struct Article: Hashable, Identifiable, Equatable, Codable {
    // sourcery: customMock = &quot;0&quot;
    let id: Int
    let title: String
    let url: String
}
</code></pre>
<blockquote>
<p>You can use <a href="https://krzysztofzablocki.github.io/Sourcery/Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)annotations">Sourcery Annotations</a> to write the default value for the generated mock.</p>
</blockquote>
<p>Here is the code generated by <strong>Sourcery</strong>:</p>
<pre><code class="language-swift">// MARK: - Generated Article
extension Article {
    static func mock(
        id: Int = 0,
        title: String = &quot;&quot;,
        url: String = &quot;&quot;
    ) -&gt; Article {
        .init(
            id: id,
            title: title,
            url: url
        )
    }
}
</code></pre>
<p>What would you add to this list? Let me know on <a href="https://x.com/tiagodhenriques">Twitter</a>!</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://swifttoolkit.dev/posts/serverless-email-deploy">📬 Deploying an Email System with SwiftCloud</a></h2>
<p>Recently, <a href="https://x.com/natanrolnik">Natan</a> from <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> introduced a feature on his website allowing readers to subscribe to email updates for new posts.
This week, he partnered with <a href="https://x.com/andrew_barba">Andrew</a> to create a hands-on video using <strong>SwiftCloud</strong>, showcasing a quick recap of his mailing system built entirely in <strong>Swif</strong>.</p>
<p>If you are considering adding a Swift-based mailing system to your newsletter, this resource is definitely worth exploring!</p>
<h2><a href="https://www.artemnovichkov.com/blog/create-ml">🤖 Creating ML models with Create ML</a></h2>
<p><a href="https://x.com/iosartem">Artem</a> recently concluded his series on text analysis with a post detailing how to create a custom machine learning model for sentiment analysis in new languages using Apple's <strong>Create ML</strong> tool.</p>
<p>Though I hadn’t tried <strong>Create ML</strong> before, this article highlighted how straightforward it is to use without requiring extensive machine learning expertise.
With a strong dataset, it serves as an excellent starting point for building machine learning models for your apps!</p>
<h2><a href="https://www.swiftwithvincent.com/blog/bad-practice-not-using-the-modern-formatting-api">❌ Bad practice: not using the modern formatting API</a></h2>
<p><strong>DateFormatter</strong> is incredibly handy but can be prone to errors!
Mistakes like using an incorrect format or creating too many instances can harm performance.</p>
<p>Since <strong>iOS 15</strong>, Apple introduced a cleaner, more efficient <strong>API</strong> for formatting values.
In this brief post, <a href="https://x.com/v_pradeilles">Vincent</a> provides an excellent introduction to this modern approach, showing how you can start leveraging it to simplify and optimize your apps.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Tools</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/25.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🦺 Making your own custom Optional 👌]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue24</link>
            <guid>24</guid>
            <pubDate>Mon, 02 Dec 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Swift's Optional type ensures safer code by clearly managing values that may or may not exist! While Swift natively supports Optionals with (?), some libraries or frameworks lack this syntax.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #24</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><strong>Swift's</strong> Optional type ensures safer code by clearly managing values that may or may not exist!
While <strong>Swift</strong> natively supports Optionals with <code>(?)</code>, some libraries or frameworks lack this syntax.</p>
<p>A common <strong>iOS</strong> interview question is: <strong>How can you create a custom Optional?</strong></p>
<p>Here is a quick implementation:</p>
<pre><code class="language-swift">// MARK: - Optional is an enum with two cases: some value and none (nil)
enum CustomOptional&lt;T&gt; {
    case some(T)
    case none

    var value: T? {
        switch self {
        case .some(let value):
            return value
        case .none:
            return nil
        }
    }

    func unwrapped() throws -&gt; T {
        switch self {
        case .some(let value):
            return value
        case .none:
            throw CustomOptionalError.valueIsNil
        }
    }

    // MARK: - Custom Optional Error enum
    enum CustomOptionalError: Error {
        case valueIsNil
    }
}

// MARK: - Initializing the value
let customOptionalString: CustomOptional&lt;String&gt; = .some(&quot;hello world!&quot;)
do {
    let value = try customOptionalString.unwrapped()
    print(&quot;Custom optional string value unwrapped: \(value)&quot;)
} catch {
    print(error)
}

let customOptionalIntNoValue: CustomOptional&lt;Int&gt; = .none
do {
    let value = try customOptionalIntNoValue.unwrapped()
    print(&quot;Custom optional int value unwrapped: \(value)&quot;)
} catch {
    print(error)
}
</code></pre>
<p>Here is the console output:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue24/custom_optional_output.webp&quot;
alt=&quot;Custom Optional output.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue24/custom_optional_output.webp&quot;
caption=&quot;Custom Optional output.&quot;
priority={true}
/&gt;</p>
<p>Mastering optionals is key to writing reliable <strong>Swift</strong> code.
Creating custom optional types helps understand their structure and allows extension for specific needs.
Whether preparing for interviews or deepening knowledge of <strong>Swift</strong>, becoming proficient in optionals strengthens your skills as an <strong>iOS</strong> developer 💪!</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.artemnovichkov.com/blog/working-with-natural-language-framework">👅 Working with Natural Language framework</a></h2>
<p>Part 2 of <a href="https://x.com/iosartem">Artem's</a> <strong>SwiftUI</strong> text editing series dives into the <strong>Natural Language framework</strong>, showcasing its real time text analysis capabilities.</p>
<p>I am surprised this framework isn't used more often.
It is a powerful tool for text analysis — free, fast, and fully functional offline!</p>
<h2><a href="https://www.youtube.com/watch?v=tbx_T2dwoFI">🧰 Mastering Swift for Scripting &amp; Tooling</a></h2>
<p><a href="https://x.com/natanrolnik">Natan's</a> <a href="https://swiftconnection.io/">Swift Connection</a> 2024 talk is now available, and it is one I have been eagerly anticipating!
I have been following Natan's work for a while, and I am a big fan of his clear, engaging teaching style!</p>
<p>If you are interested in scripting, tooling, or deepening your Swift expertise, this is a must-watch talk!</p>
<h2><a href="https://blog.jacobstechtavern.com/p/static-dynamic-mergeable-oh-my">🤦‍♂️ Static, Dynamic, Mergeable, oh, my!</a></h2>
<p>How do <strong>static</strong> and <strong>dynamic</strong> linking impact build times?</p>
<p>If this concept feels unclear, I recommend checking out <a href="https://x.com/jacobtechtavern">Jacob's</a> insightful explanation to clarify the differences and their effects on your builds!
It is definitely worth a read!</p>
<h2><a href="https://www.swiftwithvincent.com/blog/storing-two-types-in-the-same-variable-using-either">✌️ Storing two types in the same variable using Either</a></h2>
<p><a href="https://x.com/v_pradeilles">Vincent</a> shared a clever tutorial on refactoring code to handle mixed data types using a generic <code>Either</code> enum.
This enum supports two generic types, with each case storing an associated value of one type.
It is a versatile approach, similar to Swift's <a href="https://developer.apple.com/documentation/swift/result">Result</a> type.</p>
<p>Is it just me, or are enums amazing?</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Interviews</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/24.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🪆 Adapting Your App For Multi-Platform Support Using SwiftUI's NavigationSplitView ⚡️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue23</link>
            <guid>23</guid>
            <pubDate>Mon, 25 Nov 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[If you have been following recent issues, I built a navigation layer for SwiftUI apps. While testing my sample app in different Xcode simulators, I noticed it didn't look great on iPads or macOS! This week, I decided to build on top of my previus work to demonstrate how simple it is to support multiple platforms with SwiftUI.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #23</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>If you have been following recent issues, I built a <a href="https://github.com/henriquestiagoo/navigation-coordinator-swiftui/tree/refactor-to-coordinator-and-introduced-sheets-and-fullscreencovers">navigation layer</a> for <strong>SwiftUI</strong> apps.
While testing my sample app in different <strong>Xcode</strong> simulators, I noticed it didn't look great on <strong>iPads</strong> or <strong>macOS</strong>!</p>
<p>This week, I decided to build on top of my previus work to demonstrate how simple it is to support multiple platforms with <strong>SwiftUI</strong>.
For that, I tried out <a href="https://developer.apple.com/documentation/swiftui/navigationsplitview">NavigationSplitView</a>, a view I hadn't used before, and discovered how seamlessly it integrates with existing code, making it both intuitive and effective to implement.</p>
<blockquote>
<p>This class is particularly useful for implementing sidebar support on iPads running versions earlier than iOS 18. However, for apps targeting iOS 18 or later, the new <a href="https://developer.apple.com/design/human-interface-guidelines/sidebars">Sidebars</a> feature is the recommended approach.</p>
</blockquote>
<p><strong>NavigationSplitView</strong> is a <strong>SwiftUI</strong> component designed to create a sidebar-detail layout, where the sidebar controls the content displayed in the detail view.
This structure is ideal for apps that organize data into collections and require a detailed view for individual items, making it especially useful for <strong>iPad</strong> or <strong>macOS</strong> applications.
Using this type is quite simple and intuitive.</p>
<pre><code class="language-swift">// For two-column navigation
struct AppView: View {
    var body: some View {
        NavigationSplitView {
            // sidebar
        } detail: {
            // item details
        }
    }
}

// For three-column navigation
struct AppView: View {
    var body: some View {
        NavigationSplitView {
            // sidebar
        } content: {
            // content list
        } detail: {
            // item details
        }
    }
}
</code></pre>
<p>Integrating this new type was simple and seamless.
I created a <strong>SwiftUI</strong> view named <code>SidebarView</code> to display my list of issues, including a binding property to track the currently selected issue.</p>
<pre><code class="language-swift">struct SidebarView: View {
    @Binding var selectedIssue: Issue?

    var body: some View {
        List(
            Issue.sortedMocks,
            selection: $selectedIssue
        ) { issue in
            NavigationLink(value: issue) {
                IssueRowView(issue: issue)
            }
        }
        .navigationTitle(&quot;Issues&quot;)
    }
}
</code></pre>
<p>My root view now incorporates a <code>NavigationSplitView</code> for an adaptive layout across various devices and screen sizes.
I also added a <code>@State</code> property to manage the selected issue, which dynamically determines the content displayed in the detail view.</p>
<pre><code class="language-swift">struct AppView: View {
    [...]
    @State private var selectedIssue: Issue?

    var body: some View {
        NavigationSplitView {
            SidebarView(selectedIssue: $selectedIssue)
               
        } detail: {
            if let selectedIssue = selectedIssue {
                IssueView(issue: selectedIssue)
            } else {
                Text(&quot;Choose any article to view its details.&quot;)
            }
        }
    }
}
</code></pre>
<blockquote>
<p>If you are only interested in the code, here is the <a href="https://github.com/henriquestiagoo/ios-navigation-split-view/tree/main">GitHub repository</a>.</p>
</blockquote>
<p>With just a few adjustments, I was able to deliver a consistent and user-friendly interface for my sample app across <strong>iPhone</strong>, <strong>iPad</strong> and <strong>macOS</strong>.
Here is the final result:</p>
<p>&lt;StaticSmallImage
src=&quot;/issues/issue23/app_iphone.webp&quot;
alt=&quot;iOS Coffee Break Sample App running on iPhone.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue23/app_iphone.webp&quot;
caption=&quot;iOS Coffee Break Sample App running on iPhone.&quot;
priority={true}
/&gt;</p>
<p>&lt;StaticImage
src=&quot;/issues/issue23/app_ipad.webp&quot;
alt=&quot;iOS Coffee Break Sample App running on iPad.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue23/app_ipad.webp&quot;
caption=&quot;iOS Coffee Break Sample App running on iPad.&quot;
priority={true}
/&gt;</p>
<p>&lt;StaticImage
src=&quot;/issues/issue23/app_macOS.webp&quot;
alt=&quot;iOS Coffee Break Sample App running on macOS.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue23/app_macOS.webp&quot;
caption=&quot;iOS Coffee Break Sample App running on macOS.&quot;
priority={true}
/&gt;</p>
<p>For reference, if you want to learn more about <code>NavigationSplitView</code>, you can check out this <a href="https://developer.apple.com/videos/play/wwdc2022/10054/">video</a> from WWDC 2022 or take a look at <a href="https://developer.apple.com/documentation/swiftui/food_truck_building_a_swiftui_multiplatform_app">Food Truck sample code</a>, Apple's sample app on how to build a <strong>SwiftUI</strong> multiplatform app.</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://blog.jacobstechtavern.com/p/impress-at-job-interviews-by-decompiling">🤓 Impress at Job Interviews by Inspecting their App Bundle</a></h2>
<p>In his article, <a href="https://x.com/jacobtechtavern">Jacob</a> shared a pratical technique for inspecting and analyzing app bundles. By downloading an <code>.ipa</code> file, converting it into a <code>.zip</code> file, and unzipping it, you can explore its contents.</p>
<p>This method can be especially useful for learning or preparing for interviews - just ensure you are ready to address questions on this topic!</p>
<h2><a href="https://www.matthollyhead.dev/blog/Exploring-SF-Symbols-Where-to-Start-and-How/">🔣 Exploring SF Symbols: Where to Start and How to Use Them (Part 1)</a></h2>
<p><strong>SF Symbols</strong> have been around for some time, but with <strong>Apple</strong> introducing animated <strong>SF Symbols</strong> at this year's <strong>WWDC</strong>, <a href="https://x.com/Matt_B4DG3R">Matt</a> wrote a detailed article on the current state of these icons.</p>
<p>Even if you are familiar with how <strong>SF Symbols</strong> function, this article is a great refresher and might teach you something new!</p>
<h2><a href="https://codingwithvera.com/upgrade-your-pull-requests-with-chatgpt/">🤖 Upgrade Your Pull Requests With ChatGPT</a></h2>
<p><a href="https://x.com/CodingWithVera">Vera</a> shared a valuable tip this week on using <strong>AI</strong> to enhance <strong>Pull Requests</strong>.
She recommends leveraging <strong>ChatGPT</strong> to create <strong>UML</strong> diagrams quickly, saving time and adding clarity to your <strong>PRs</strong>.</p>
<p>While I hadn't considered including diagrams in my <strong>PRs</strong> before, this approach seems practical — just make sure the diagrams are accurate and relevant!</p>
<h2><a href="https://medium.com/macoclock/private-swift-package-manager-a-better-way-to-share-your-code-96e863d31c27">🛡️ Private Swift Package Manager: A Better Way to Share Your Code</a></h2>
<p><a href="https://x.com/chromicle_3">Ajay</a> shared an insightful article on distributing <strong>private Swift Packages</strong> efficiently without managing individual repository access or manual framework updates.</p>
<p>His approach consists in a clever use of <strong>fine-grained tokens</strong> that ensures a seamless experience for users, keeps your code secure, and gives you full control — allowing token revocation or updates anytime.</p>
<h2><a href="https://x.com/v_pradeilles/status/1859213383977111601">🤯 New Xcode 16 Feature</a></h2>
<p><a href="https://x.com/v_pradeilles">Vincent</a> recently highlighted a handy new feature in <strong>Xcode</strong> 16 that I hadn't noticed before but is sure to streamline your workflow!</p>
<p>You can now paste content directly into the Project Navigator, and <strong>Xcode</strong> will automatically generate a new file with an appropriate name.
One caveat I observed is that imports are missing in the generated file, though hopefully, future updates will address this!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Multi-Platform</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/23.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👷 Refactoring my SwiftUI Navigation Layer to follow the Coordinator Pattern 🔀]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue22</link>
            <guid>22</guid>
            <pubDate>Mon, 18 Nov 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Recently, I implemented a navigation layer for my SwiftUI apps, initially handling only stacked screen navigation. I left out sheet and full-screen presentations, planning to add them later. Now, I am back to refactor the layer, expanding it to handle these additional presentation types for more versatile navigation options.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #22</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>I strongly support a clear separation of concerns for a clean design pattern, and in my experience, separating navigation logic from views is essential for scalability.
Recently, I implemented a navigation layer for my <strong>SwiftUI</strong> apps, initially handling only <strong>stacked</strong> screen navigation.
I left out <strong>sheet</strong> and <strong>full-screen</strong> presentations, planning to add them later.</p>
<p>So, this week, I published an <a href="https://www.tiagohenriques.dev/blog/swiftui-refactor-navigation-layer-using-coordinator-pattern">article</a> on refactoring my navigation layer to handle additional presentation types, enabling more versatile navigation.
I transitioned from a <strong>Router</strong> to a <strong>Coordinator</strong> model and the picture below illustrates how I can navigate the app after the update.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue22/coordinators_diagram.webp&quot;
alt=&quot;Coordinators Diagram.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue22/coordinators_diagram.webp&quot;
caption=&quot;Coordinators Diagram.&quot;
priority={true}
/&gt;</p>
<p>The main objective was to transition from a linear navigation stack to a distinct set of independent navigation screens using a sheet presentation.
Here is a quick demo from the <a href="https://github.com/henriquestiagoo/navigation-coordinator-swiftui/tree/refactor-to-coordinator-and-introduced-sheets-and-fullscreencovers">sample project</a> I have set up:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue22/swiftui-routing-layer-sheet.gif&quot;
alt=&quot;SwiftUI Navigation Layer Sheet Demo.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue22/swiftui-routing-layer-sheet.gif&quot;
caption=&quot;SwiftUI Navigation Layer Sheet Demo.&quot;
priority={true}
/&gt;</p>
<p>My initial Router setup handled navigation for a single screen, while my updated <strong>Coordinator-based</strong> navigation layer supports nesting, with parent Coordinators managing child Coordinators to enable complex hierarchical navigation flows throughout the app.</p>
<p>If you have thoughts or personal experiences with <strong>SwiftUI</strong> navigation, I would love to hear them — feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a>!</p>
<blockquote>
<p>If you are only interested in the code, here is the <a href="https://github.com/henriquestiagoo/navigation-coordinator-swiftui/tree/refactor-to-coordinator-and-introduced-sheets-and-fullscreencovers">GitHub repository</a>.</p>
</blockquote>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.polpiella.dev/how-to-use-the-github-cli-from-github-actions-workflows/">💡 Automate GitHub Tasks with GitHub CLI in Actions Workflows: A Step-by-Step Guide</a></h2>
<p>Did you know that <strong>GitHub-hosted</strong> runners come with the <strong>GitHub CLI</strong> pre-installed? I wasn't aware either!
By combining the <strong>GitHub CLI</strong> with <strong>GitHub Actions</strong> workflows, you can streamline tasks that typically require manual effort.</p>
<p><a href="https://x.com/polpielladev">Pol's</a> latest article dives into using the <strong>GitHub CLI</strong> with the provided token in workflows to automate tasks like creating pull requests or managing issues, reducing friction and improving efficiency.</p>
<h2><a href="https://nilcoalescing.com/blog/PreviewSwiftUIViewsWithBindings/">✨ Preview SwiftUI views with bindings using @Previewable</a></h2>
<p>Starting with <strong>Xcode 16</strong>, the new <strong>Previewable</strong> macro simplifies previewing <strong>SwiftUI</strong> views that use bindings.</p>
<p><a href="https://x.com/natpanferova">Natalia's</a> recent post offers a quick guide on how to apply it.
This addition is highly practical, as it allows for fully interactive previews without needing to embed state within child views, streamlining the preview process.</p>
<h2><a href="https://www.linkedin.com/posts/romain-brunie-the-composable-architecture_github-copilot-for-xcode-uses-tca-weve-activity-7262736049020305409-EGH5/">🤯 GitHub Copilot for Xcode Uses TCA!</a></h2>
<p>Recently, <strong>GitHub</strong> launched <a href="https://github.com/github/CopilotForXcode">GitHub Copilot for Xcode</a>, an extension designed to simplify using their <strong>AI</strong> assistant directly within <strong>Xcode</strong>.</p>
<p>In a post, <a href="https://www.linkedin.com/in/romain-brunie-the-composable-architecture/">Romain</a> pointed out that this new extension runs with <a href="https://github.com/pointfreeco/swift-composable-architecture">TCA</a> (The Composable Architecture), making it even more appealing to developers who rely on this library.
It is exciting to see increasing adoption of <a href="https://www.pointfree.co/">Point-Free's</a> composable architecture by individuals and companies alike.
What are your thoughts on <strong>TCA</strong> and its growing popularity?</p>
<h2><a href="https://www.artemnovichkov.com/blog/mastering-text-editor-in-swiftui">✍️ Mastering TextEditor in SwiftUI: Features, Limitations, and Tips</a></h2>
<p><a href="https://x.com/iosartem">Artem's</a> latest article dives into the fundamentals of <a href="https://developer.apple.com/documentation/swiftui/texteditor">TextEditor</a> in <strong>SwiftUI</strong> and demonstrates how to enhance it with added features.</p>
<p>This is the first article in a series focusing on text editing. Upcoming articles will delve into topics like text classification and creating custom machine learning models for text analysis.
I am super excited to follow along as this series unfolds!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Navigation</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/22.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🚧 Manage SwiftUI Navigation using the Router Pattern 🚌]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue21</link>
            <guid>21</guid>
            <pubDate>Sun, 10 Nov 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Views on SwiftUI's navigation are divided: some developers support it fully, while others feel it is not yet robust enough for complex apps, even with NavigationStack. An appropriate design pattern can be beneficial to decouple view logic from navigation code.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>issue #21</strong> of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Views on <strong>SwiftUI's</strong> navigation are divided: some developers support it fully, while others feel it is not yet robust enough for complex apps, even with <code>NavigationStack</code>.</p>
<p>This week, I published an <a href="https://www.tiagohenriques.dev/blog/swiftui-navigation-router-pattern">article</a> introducing the <strong>Router</strong> pattern in <strong>SwiftUI</strong>, explaining why it is beneficial and how to implement it effectively.
The <strong>Router</strong> pattern helps you keep navigation logic separate from your views, making your app more maintainable and scalable in the long run.</p>
<p>The <strong>Router</strong> approach, ideal for programmatic and adaptable navigation, offers significant flexibility.
It is particularly effective for apps with complex or conditional navigation flows, allowing developers to structure navigation tailored precisely to the app's requirements.</p>
<blockquote>
<p>If you are only interested in the code, here is the <a href="https://github.com/henriquestiagoo/navigation-router-swiftui/tree/navigation-router">GitHub repository</a>.</p>
</blockquote>
<p>Here is a quick demo from the sample project I have set up:</p>
<p>&lt;StaticImage
src=&quot;/issues/issue21/router_navigation_demo.gif&quot;
alt=&quot;SwiftUI Navigation Demo using the Router Pattern.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue21/router_navigation_demo.gif&quot;
caption=&quot;SwiftUI Navigation Demo using the Router Pattern.&quot;
priority={true}
/&gt;</p>
<p>The navigation router could be enhanced to handle other types of transitions, like <strong>sheet</strong> presentations or <strong>full-screen</strong> views, in addition to the navigation stack.
I am planning to add these features over the next few weeks — stay tuned!</p>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.polpiella.dev/automate-code-signing-with-fastlane-match/">✍️ Automate Apple app code signing using fastlane match</a></h2>
<p><a href="https://x.com/polpielladev">Pol's</a> article offers a friendly guide to automating code signing with <a href="https://docs.fastlane.tools/actions/match/">Fastlane Match</a>, covering the basics and providing a step-by-step tutorial.
This can be a huge time-saver, especially for large teams, as it helps avoid redundancy and streamlines updates to signing identities when adding devices or new team members.</p>
<p>For teams managing certificates manually or through automation, it is a highly recommended read to minimize potential confusion and improve efficiency.</p>
<h2><a href="https://swifttoolkit.dev/posts/dev-containers-swift">🫙 Developing in Swift with VS Code Dev Containers</a></h2>
<p>Imagine if we could eliminate the <code>&quot;it works on my machine&quot;</code> issue entirely 🤔!</p>
<p>In the first of a three-part series, Natan from <a href="https://x.com/SwiftToolkit">Swift Toolkit</a> walks through using VS Code, Dev Containers, and GitHub Codespaces to develop and debug Swift applications on Linux.</p>
<p>This article provides a practical guide on setting up VS Code on your local machine with Dev Containers, enabling a smooth <strong>Swift</strong> development and debugging experience across environments.</p>
<h2><a href="https://x.com/tuistdev/status/1854947458201137476">🧙‍♀️ Bringing Tuist Previews forward</a></h2>
<p>Testing the application is a vital part of the development process, catching bugs 🐛 early makes them easier to locate and resolve.</p>
<p>With <a href="https://x.com/tuistdev">Tuist's</a> latest preview enhancements, launching the app from any branch, specific commit, or the latest repository update is now just one command away.
I am definitely thrilled to give this feature a try!</p>
<pre><code class="language-sh">tuist run App@latest # run latest preview from you default branch
tuist run App@feature-branch # run preview from a specified branch
tuist run App@91eb7c # run preview from a specific commit
</code></pre>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Navigation</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/21.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🧑‍✈️ GitHub Copilot for Xcode is now available! ✈️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue20</link>
            <guid>20</guid>
            <pubDate>Sun, 03 Nov 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, GitHub revealed that GitHub Copilot's code completion feature is now available in public preview for Xcode! GitHub Copilot, an AI-powered coding assistant, helps streamline and enhance your coding process.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>20th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>This week, <strong>GitHub</strong> revealed that <a href="https://github.blog/changelog/2024-10-29-github-copilot-code-completion-in-xcode-is-now-available-in-public-preview/">GitHub Copilot's</a> code completion feature is now available in public preview for Xcode!
<strong>GitHub Copilot</strong>, an AI-powered coding assistant, helps streamline and enhance your coding process.
<a href="https://github.com/github/CopilotForXcode">Copilot for Xcode</a> is an <strong>Xcode</strong> extension that provides inline coding suggestions as you type.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue20/github_copilot.gif&quot;
alt=&quot;GitHub Copilot demo from GitHub's repository.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue20/github_copilot.gif&quot;
caption=&quot;GitHub Copilot demo from GitHub's repository.&quot;
priority={true}
/&gt;</p>
<h3>Key Features:</h3>
<ul>
<li><strong>Code Completions:</strong> Integrated in Xcode, providing inline code suggestions.</li>
<li><strong>Multi-Language Support:</strong> Compatible with Swift, Objective-C, and other Apple ecosystem languages.</li>
<li><strong>Multiline Suggestions:</strong> Default single-line suggestions, with multi-line options accessed by holding the Option key and pressing Option + Tab.</li>
<li><strong>Content Filtering:</strong> Uses filters to prevent inappropriate content, maintaining a professional coding environment.</li>
<li><strong>Public Code Blocker:</strong> Includes a filter to block suggestions that resemble public GitHub code, preventing code duplication.</li>
</ul>
<h3>Requirements:</h3>
<ul>
<li><strong>macOS 12+</strong></li>
<li><strong>Xcode 8+</strong></li>
<li><strong>A GitHub Copilot subscription.</strong> To learn more, visit the official <a href="https://github.com/features/copilot">page</a>.</li>
</ul>
<h2>Initial Impressions</h2>
<p>I tested it briefly on some sample code, and it feels like a solid improvement over <strong>Xcode 16's</strong> local predictive model.
It is quicker, more precise, and can auto-generate longer code snippets.
I will need to spend more time with it for a thorough review, though!</p>
<p>While I don't see myself subscribing for a feature like this, I am always curious to explore these tools and see what they can offer!</p>
<blockquote>
<p>For a guide on how to get started, check the <a href="https://docs.github.com/en/copilot/managing-copilot/configure-personal-settings/installing-the-github-copilot-extension-in-your-environment?tool=xcode">docs</a> from GitHub.</p>
</blockquote>
<p>Now it is time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://codingwithvera.com/the-strategy-pattern/">🧜‍♀️ The Strategy Pattern</a></h2>
<p>Do you aim to simplify when adding new features to existing code?
This week, <a href="https://x.com/CodingWithVera">Vera</a> offers her insights on using the <strong>Strategy</strong> pattern to encapsulate and swap different behaviors with ease.</p>
<p>My advice: take a page from <strong>Vera's</strong> playbook to avoid turning your &quot;birds&quot; into &quot;merm-birds&quot;!</p>
<blockquote>
<p>P.S. You might neeed to read the article to get this one!</p>
</blockquote>
<h2><a href="https://vbat.dev/coordinators-swiftui">🚣‍♂️ Coordinators &amp; SwiftUI</a></h2>
<p>Views on <strong>SwiftUI's</strong> navigation are divided: some developers support it fully, while others feel it is not yet robust enough for complex apps, even with <code>NavigationStack</code>.
I have to admit, my team and I currently use <strong>SwiftUI</strong> for UI design, but still handle navigation with <strong>UIKit</strong> by embedding <strong>SwiftUI</strong> views in <code>UIHostingController</code> — especially since we support <strong>iOS 15</strong> and can't use <code>NavigationStack</code> at its full power yet!</p>
<p>In this article, <a href="https://x.com/vitaly_batrakov">Vitaly</a> investigates whether <strong>SwiftUI</strong>, specifically <code>NavigationStack</code>, can support the <strong>Coordinator</strong> pattern. He explores adapting this approach to <strong>SwiftUI</strong> and demonstrates building a streamlined <strong>SwiftUI</strong> <strong>Coordinator</strong> without complex third-party libraries.</p>
<blockquote>
<p>Vitaly also offers a <a href="https://www.youtube.com/watch?v=SaKWfvGi5rA">video</a> version of this article if you would rather watch than read.</p>
</blockquote>
<h2><a href="https://www.polpiella.dev/bump-numbers-ci-cd/">🤖 How to automatically update build and version numbers in your app using Fastlane</a></h2>
<p>In this article, <a href="https://x.com/polpielladev">Pol</a> demonstrates how to use <strong>Fastlane</strong> to streamline updating your app's build and version numbers.</p>
<p>By automating this process, you can ensure your app's version and build numbers are always current before deploying a new release, saving time and reducing errors!</p>
<h2><a href="https://swiftonserver.com/getting-started-with-swift-package-manager/">👶 Getting Started with Swift Package Manager</a></h2>
<p>If you are new to <strong>Swift Packages</strong> and looking to create <strong>CLI</strong> executables or <strong>library</strong> targets, this article is a must-read!
<a href="https://x.com/JoannisOrlandos">Joannis</a> explains the essentials of <strong>Swift Package Manager</strong>, walking you through creating a package, adding dependencies, and linking target dependencies.</p>
<blockquote>
<p>Interesting fact: With <strong>SwiftPM</strong>, you can choose to add dependencies by either editing the manifest <code>(Package.swift)</code> directly or by using the <strong>CLI</strong> tool — both approaches work seamlessly.</p>
</blockquote>
<h2><a href="https://www.avanderlee.com/swift/blog-about-swift/">💡 Blog about Swift: Tips and ideas to start your own</a></h2>
<p>Recently, I found an article <a href="https://x.com/twannl">Antoine</a> shared a few years back that I wish I had seen when I first started blogging about <strong>Swift</strong>!</p>
<p>If you are already blogging about <strong>Swift</strong> or planning to start, this article shares <strong>Antoine's</strong> top tips for writing <strong>Swift</strong> content effectively.
It is full of best practices, so definitely check it out!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>AI</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/20.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🥷 Migrating workflows from TeamCity to Xcode Cloud ☁️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue19</link>
            <guid>19</guid>
            <pubDate>Sun, 27 Oct 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Last week, I have been migrating our CI/CD pipelines from TeamCity to Xcode Cloud. Xcode Cloud is a Continuous Integration and Continuous Delivery (CI/CD) platform provided by Apple.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>18th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Last week, I have been migrating our <strong>CI/CD</strong> pipelines from <a href="https://www.jetbrains.com/teamcity/">TeamCity</a> to <a href="https://developer.apple.com/xcode-cloud/">Xcode Cloud</a>.
<strong>Xcode Cloud</strong> is a Continuous Integration and Continuous Delivery (CI/CD) platform provided by <strong>Apple</strong>. It automates away the hard work of building your apps, testing them, signing them, and pushing them to a destination.</p>
<p>With all project external dependencies now managed through <strong>SPM</strong>, the transition to <strong>Xcode Cloud</strong> was seamless. I had just encountered some few minor issues, but they were quickly resolved.</p>
<h3>Workflow 1: Changes to the main branch</h3>
<p>The first workflow was set up to <strong>run unit tests</strong> on every push to the <strong>main</strong> branch and on pull requests (PRs) targeting <strong>main</strong>.
Additionally, it alerts the team once all tests pass, confirming it is safe to merge into <strong>main</strong>.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue19/xcode_cloud_workflow1.webp`&quot;
alt=&quot;Xcode Cloud workflow that runs tests and notifies the result.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue19/xcode_cloud_workflow1.webp&quot;
caption=&quot;Xcode Cloud workflow that runs tests and notifies the result.&quot;
priority={true}
/&gt;</p>
<h3>Workflow 2: Releases</h3>
<p>The second workflow migration triggers on every push to the <code>release/XXX/qa</code> branch, archiving the app and distributing it to TestFlight for external testing.</p>
<p>To keep versioning clear, we append the version number to the branch name, formatted as <code>release/XXX/qa/Y.Y.Y</code>.
A similar workflow was also created for archiving and uploading to production.</p>
<blockquote>
<p>The <code>XXX</code> indicates the client brand but can be replaced by any identifier that makes sense for your project setup.</p>
</blockquote>
<p>&lt;StaticImage
src=&quot;/issues/issue19/xcode_cloud_workflow2.webp&quot;
alt=&quot;Xcode Cloud workflow that archives and uploads to TestFlight.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue19/xcode_cloud_workflow2.webp&quot;
caption=&quot;Xcode Cloud workflow that archives and uploads to TestFlight.&quot;
priority={true}
/&gt;</p>
<p>I am currently focused on migrating the remaining workflows and looking for ways to extend the existing ones.
Wish me luck 🤞!</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://swifttoolkit.dev/posts/argument-parser-custom">🛠️ A Different Approach Using the Swift Argument Parser</a></h2>
<p>Using <strong>Swift Argument Parser</strong> is quite intuitive, but sometimes you might need added flexibility for custom output or workflows.</p>
<p>In this post by <a href="https://x.com/SwiftToolkit">Swift Toolkit</a>, <strong>Natan</strong> explores advanced techniques like custom output styles and flows with protocol-driven commands.
If you are into <strong>tooling</strong> and <strong>scripting</strong>, all using the <strong>Swift</strong> programming language, <a href="https://swifttoolkit.dev/">Swift Toolkit</a> is the website you should bookmark!</p>
<h2><a href="https://peterfriese.dev/blog/2024/delay-task-modifier/">🕶 Improve your app's UX with SwiftUI's task view modifier</a></h2>
<p>SwiftUI's <code>.task</code> modifier acts as an asynchronous combination of <code>.onAppear</code> and <code>.onDisappear</code>, starting a task when a view appears and canceling it if the view exits first.</p>
<p>Recently, <a href="https://x.com/peterfriese">Peter</a> needed to add a delay before running specific code and created a reusable <code>DelayTaskViewModifier</code>, inspired by <strong>Combine's</strong> functionality.
This modifier allows tasks to run after a short delay, enhancing control within <strong>SwiftUI</strong> workflows.</p>
<h2><a href="https://medium.com/@SaezChristopher/nitpicking-during-code-review-is-just-a-waste-of-time-invest-in-tooling-instead-07ae29f4a56a">🚫 Nitpicking during code review is just a waste of time. Invest in tooling instead.</a></h2>
<p><strong>Nitpicking</strong> can be subjective and often leads to unnecessary debates that sidetrack higher-impact issues. The true is that the line between necessary changes and nitpicking can be blurry!</p>
<p><a href="https://x.com/SaezChristopher">Christopher</a> suggests that nitpicking often stems from gaps in tools, automation, and conventions — a point I fully agree with!
The key is to replace <strong>nitpicking</strong> with <strong>effective tooling</strong>.</p>
<p>For those interested in streamlining their review process, this article offers practical recommendations on tools to support your team and keep feedback productive!</p>
<blockquote>
<p>Nitpicking stands as the finding or pointing out of minor faults in a fussy or pedantic way.</p>
</blockquote>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CI/CD</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/19.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👀 Reaching (almost) my personal goals for 2024! 🏋🏼‍♀️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue18</link>
            <guid>18</guid>
            <pubDate>Sun, 20 Oct 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Earlier this year, I set several personal milestones, and as we enter the final quarter, I am happy to say that the only goal I haven't hit yet is going to the gym four times a week 😅🏋🏼‍♀️! On the bright side, I have not only posted more on my blog, but I also built this newsletter from scratch, which now has over 250 email subscribers and is close to 1k unique visitors!]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>18th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>&lt;StaticTweet id=&quot;1744330816560222634&quot; /&gt;</p>
<p>Earlier this year, I set several personal milestones, and as we enter the final quarter, I am happy to say that the only goal I haven't hit yet is going to the gym <strong>four</strong> times a week 😅🏋🏼‍♀️! I mean, it is crazy right?</p>
<p>On the bright side, I have not only posted more on my <a href="https://www.tiagohenriques.dev/">blog</a>, but I also built this newsletter from scratch, which now has over <code>250</code> email subscribers and is close to <code>1k</code> unique visitors!
It's been an amazing motivator to continue writing and delivering value for free to the <strong>iOS</strong> community.</p>
<p>This is the driving force behind it all!
I have spent countless hours searching for valuable resources and often wished there was a single place to find them effortlessly.
Now, there is, and it is called <strong>iOS Coffee Break</strong> ☕!</p>
<p>&lt;StaticImage
src=&quot;issues/issue18/plausible_metrics_till_oct_2024.webp&quot;
alt=&quot;iOS Coffee Break website metrics since May 2024.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue18/plausible_metrics_till_oct_2024.webp&quot;
caption=&quot;iOS Coffee Break website metrics since May 2024.&quot;
priority={true}
/&gt;</p>
<blockquote>
<p>I love sharing free content to help fellow developers. Your support means a lot! Please follow me on <a href="https://www.linkedin.com/in/tiagofighenriques/">LinkedIn</a>, <a href="https://github.com/henriquestiagoo">GitHub</a>, and <a href="https://x.com/tiagodhenriques">Twitter</a>.
Let’s connect, collaborate, and grow together! 🚀</p>
</blockquote>
<p>Now it's time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://swiftrocks.com/working-at-startups-vs-large-companies">🏎 Working at startups vs large companies</a></h2>
<p>Who hasn’t dreamed of working at top companies like <strong>Apple</strong>, <strong>Google</strong>, or <strong>Amazon</strong>? I know I did...
In a non-technical article, <a href="https://x.com/rockbruno_">Bruno</a> explores the differences between working for companies of various sizes, helping you figure out which type of organization aligns best with your style and interests.</p>
<p>I highly recommend checking out this piece to gain insights into the <strong>pros</strong> and <strong>cons</strong> of working for larger versus smaller companies.</p>
<h2><a href="https://codingwithvera.com/why-do-uiviewcontrollers-need-init-coder/?ref=coding-with-vera-newsletter">⚠️ Why Do View Controllers Need init(coder:)?</a></h2>
<p>If you have ever written a <code>UIViewController</code> in <strong>UIKit</strong> without <strong>Storyboards</strong> or <strong>XIBs</strong>, you have likely come across the <code>init(coder:)</code> error.
<a href="https://x.com/CodingWithVera">Vera's</a> latest article dives into why this initializer is required when creating view controllers programmatically.</p>
<p>If you are curious about the details behind this error and how to handle it, it is definitely worth a read!</p>
<h2><a href="https://www.avanderlee.com/optimization/developer-productivity-boost-with-google-search-tips-tricks/">🔍 Developer productivity boost with Google Search Tips &amp; Tricks</a></h2>
<p>One of the key skills for any developer is knowing how to perform efficient searches.
This week, <a href="https://x.com/twannl">Antoine</a> shared valuable tips on improving your search results using <strong>Google</strong>. These include tricks like utilizing the wildcard <strong>asterisk (*)</strong> and limiting searches to specific <strong>domains</strong>, among others.</p>
<p>His insights are definitely worth checking out if you are looking to level up your search game!</p>
<h2><a href="https://www.polpiella.dev/install-ruby-and-gems-on-ci-cd">☁️ How to install the same version of Ruby and Fastlane locally and on CI/CD</a></h2>
<p>Ensuring <strong>tooling consistency</strong> is essential for maintaining <strong>stability</strong> — making sure that every team member uses the same versions of tools and dependencies across <strong>local</strong> environments and <strong>CI/CD</strong> systems.</p>
<p><a href="https://x.com/polpielladev">Pol's</a> latest article goes through this topic and how to set up and install <strong>Ruby</strong> and <strong>Fastlane</strong> reliably with <strong>GitHub Actions</strong>.
If you are interested into iOS <strong>CI/CD</strong> development topics, I highly recommend you subscribing to his <a href="https://www.ioscinewsletter.com/">newsletter</a>.</p>
<h2><a href="https://calincrist.com/the-perfect-ios-networking-layer-does-not-exist---part-2">🧱 The perfect iOS networking layer does not exist - Part 2</a></h2>
<p>Every <strong>iOS</strong> developer is likely familiar with building a custom <strong>networking layer</strong>, and many have probably refactored their own network clients, as I did with mine, <a href="https://github.com/henriquestiagoo/Carrots">Carrots</a> 🥕.
The constant question remains: <em>&quot;Is it good enough, or can it be improved?&quot;</em></p>
<p>In a series of articles, <a href="https://x.com/calin_crist">Calin</a> shares his approach to creating a modular, extensible, and testable <strong>networking layer</strong> in <strong>Swift</strong>.
His latest release focuses on writing unit and integration tests for components like <code>APIClient</code>, <code>Middleware</code>, and <code>APIService</code> — a great resource for developers at any level.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/18.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🏟️ Wrapping up 3 unique days of SwiftLeeds 2024 🍺]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue17</link>
            <guid>17</guid>
            <pubDate>Fri, 11 Oct 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[SwiftLeeds has come to a close, and I am so glad I could attend this fantastic event! It was my first iOS conference, and I couldn't have picked a better one. Even though I went solo, I never felt alone — everyone was so welcoming and friendly.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>17th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><a href="https://x.com/swift_leeds">SwiftLeeds</a> has come to a close, and I am so glad I could attend this fantastic event!
It was my first <strong>iOS</strong> conference, and I couldn't have picked a better one.</p>
<p>Even though I went solo, I never felt alone — everyone was so welcoming and friendly. Making connections was effortless.</p>
<p>🚀 Big thanks to <a href="https://x.com/Adam9Rush">Adam</a> and the entire organizing team for making this event happen!
I have made great connections that I plan to keep in touch with, and I am already excited about next year! 👀</p>
<p>&lt;StaticImage
src=&quot;issues/issue17/adam_swiftleeds.webp&quot;
alt=&quot;Adam Rush hosting SwiftLeeds 2024 - Opening Ceremony 🏟️.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue17/adam_swiftleeds.webp&quot;
caption=&quot;Adam Rush hosting SwiftLeeds 2024 - Opening Ceremony 🏟️.&quot;
priority={true}
/&gt;</p>
<h1>Talks</h1>
<p><a href="https://swiftleeds.co.uk/">SwiftLeeds 2024</a> featured a diverse range of talks, from non-technical stories like <a href="(https://www.linkedin.com/in/chloe-jenner-b1a8b9231/)">Chloe's</a> transition from teaching to mobile development and <a href="https://x.com/joshdholtz">Josh's</a> journey of overcoming his stutter, to more technical topics such as <a href="https://mastodon.social/@maxd">Max</a> introduction to <strong>WebAssembly</strong> and <a href="https://x.com/mattie">Matthew Massicotte's</a> deep dive into <strong>Swift Concurrency</strong>.</p>
<p>Among the sessions, I have chosen a few that resonated most with me and left a lasting impact.
Here is a quick look at those standout talks:</p>
<blockquote>
<p>All the talks should be available soon on the <a href="https://www.youtube.com/@swiftleeds">SwiftLeeds Youtube channel</a>.</p>
</blockquote>
<h2>From Side Project to Going Indie</h2>
<p><a href="https://x.com/twannl">Antoine</a> kicked off <a href="https://swiftleeds.co.uk/">SwiftLeeds</a> with a captivating talk about his journey to becoming an <strong>Indie developer</strong>.
From the developers I have met over the past few days, it is clear that most are working on side projects.
However, only a small portion of them are able to earn enough from these projects to fully support themselves.</p>
<p>Hopefully with <strong>Antoine's</strong> strategies and insights, we can better leverage our side projects, potentially turning them into a stepping stone for a significant career shift.</p>
<blockquote>
<p>Off topic, it was conducted a study on SwiftLeeds and Antoine is in fact the tallest iOS developer alive!</p>
</blockquote>
<h2>Cut costs, not corners - Master modularization with SPM</h2>
<p><a href="https://www.linkedin.com/in/antonio-markotic/">Antonio</a> talk about modularization with <strong>SPM</strong> was one of the most interesting ones to me because I can totally see myself into his struggles while refactoring his monolith <strong>iOS</strong> project using <strong>SPM</strong>.</p>
<p><strong>Antonio</strong> shared practical advice for working with <strong>SPM</strong>, offering helpful strategies to implement in your projects.
He highlighted common pitfalls to avoid and provided guidance on maintaining <strong>SPM</strong> projects effectively over time.
Unfortunately, I couldn't reach out to him at the end of the talks, but I will try to get to him to discuss some topics.</p>
<blockquote>
<p>For those who attended the talk, have you found the out way of the maze?</p>
</blockquote>
<h2>Fixing Image Performance for The Worst iPhone</h2>
<p><a href="https://x.com/avielgr">Aviel's</a> talk covered the image performance issues his team encountered and how they tackled them.
If you are interested in practical solutions, I highly recommend watching it when it becomes available.</p>
<p>He shared real world examples of <strong>CPU</strong> overload, <strong>OOM</strong> crashes, frame rate drops in <strong>SwiftUI</strong>, and how they managed to overcome these to maintain <code>60 FPS</code>, ensuring smooth scrolling through high resolution images.
It is definitely a great resource for anyone dealing with similar performance challenges!</p>
<h2><a href="https://www.youtube.com/watch?v=k17YKrhPU4o">From Quantum to Code: A Teacher's Journey into Mobile Development</a></h2>
<p><a href="https://www.linkedin.com/in/chloe-jenner-b1a8b9231/">Chloe Jenner's</a> debut as a conference speaker was nothing short of remarkable, delivering a poetic and deeply inspirational talk!
In a refreshing, non-technical session, <strong>Chloe</strong> shared her personal journey, transitioning from being a teacher to the fast-paced world of mobile development.</p>
<p>Her engaging storytelling and practical advice encouraged the audience to embrace their own career shifts, while highlighting the untapped potential of individuals from diverse backgrounds.
It was one of the most powerful and motivational talks I have seen!</p>
<p>For anyone feeling like they <strong>&quot;do not belong here&quot;</strong>, take a 20-minute break and let Chloe's talk change your mind!</p>
<h2>The Roast of your App's Design</h2>
<p><a href="https://x.com/hiddevdploeg">Hidde</a> delivered one of the most entertaining talks at the conference by humorously roasting two applications that clearly lacked adherence to Apple's <a href="https://developer.apple.com/design/human-interface-guidelines">Human Interface guidelines</a>.
The main issues pointed out the excessive taps required for actions, intrusive onboarding processes, misuse of animations, and failure to incorporate native components.</p>
<p>A big shoutout to <a href="https://www.linkedin.com/in/harryowenn/">Harry</a> and <a href="https://www.linkedin.com/in/antonio-markotic/">Antonio</a> for playing along and being the subject to all kinds of dutch 🇳🇱 jokes!</p>
<blockquote>
<p>As a side note, rumor has it that Harry hasn’t stopped crying since ...</p>
</blockquote>
<h2><a href="https://x.com/zerocam_app">Zerocam</a>: Indie App of the Conference (Personal choice)</h2>
<p>&lt;StaticImage
src=&quot;/issues/issue17/zerocam.webp&quot;
alt=&quot;ZeroCam App Store screenshots.&quot;
link=&quot;https://www.ioscoffeebreak.com/issues/issue17/zerocam.webp&quot;
caption=&quot;ZeroCam App Store screenshots.&quot;
/&gt;</p>
<p>I met <a href="https://x.com/ramrodser">Sergio</a> at the conference, where we talked about his passion for photography and his app, <a href="https://apps.apple.com/pt/app/zerocam-anti-ai-camera/id6483933438">Zerocam</a>.
It is a minimalist <strong>iPhone</strong> camera app designed without heavy post-processing or complex controls, offering an experience similar to a digital camera.</p>
<h3>Key Features:</h3>
<ul>
<li><strong>Natural Photography:</strong> No artificial post-processing, just RAW photos with soft, natural results.</li>
<li><strong>One-Button Simplicity:</strong> One-button operation for hassle-free shooting.</li>
<li><strong>No Distractions:</strong> No settings or mode changes, focusing solely on capturing moments.</li>
<li><strong>Lens Switching:</strong> Quick lens change via Force Touch.</li>
<li><strong>Become a Better Photographer:</strong> Join the 365 Challenge with the dedicated widget and improve your photography skills daily.</li>
</ul>
<p>If you would like to see more content focused on applications, let me know!
You can always reach out to me on <a href="https://x.com/tiagodhenriques">X</a>. Feel free to connect!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/17.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[📻 Generating podcasts from blog articles 📔]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue16</link>
            <guid>16</guid>
            <pubDate>Fri, 27 Sep 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[NotebookLM's new podcast feature is incredible! For those unfamiliar, NotebookLM is a Google-powered AI research assistant, using Gemini 1.5 Pro to help you understand complex information. Now, with the new feature, you can transform that content into a podcast! Would a podcast summary be something you would find useful to include with the weekly issue?]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>16th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><a href="https://blog.google/technology/ai/notebooklm-audio-overviews/">NotebookLM's new podcast feature</a> is incredible! For those unfamiliar, <a href="https://notebooklm.google/">NotebookLM</a> is a Google-powered <strong>AI</strong> research assistant, using <strong>Gemini 1.5 Pro</strong> to help you understand complex information.
You can upload documents like PDFs, text files or blog posts, and generate derivative works like study guides or FAQs.</p>
<p>Now, with the new feature, you can transform that content into a <strong>podcast</strong>! You read it right!
I have tested out it with my latest issue, and the results were surprisingly good.
I have noticed just one small problem in the audio but bear in mind that this feature is <strong>experimental</strong>!
It is certainly a unique way to view your own material from a new perspective.</p>
<p>Give it a listen and let me know your thoughts — would this be something you would find useful to include with the weekly issue?
This way, you could listen to my weekly podcast while driving — pretty convenient, right?</p>
<p>&lt;BasicAudioPlayer
src=&quot;/issues/issue16/ioscoffeebreaknewsletter_issue15.wav&quot;
/&gt;</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.tiagohenriques.dev/blog/image-background-remover-cli">✂️ Remove the background from images using a Swift CLI tool</a></h2>
<p>Removing image backgrounds has always been a challenge for me, either due to a lack of photoshop skills or the poor results from free online tools.</p>
<p>If you have been following the newsletter, you probably know how much I love creating <strong>Swift executables</strong>.
So, I decided to develop a <strong>Swift CLI</strong> tool that removes image backgrounds using <strong>Apple's</strong> new machine-learning features in the <a href="https://developer.apple.com/documentation/vision/">Vision</a> framework.</p>
<blockquote>
<p>My girlfriend's cat, Simba, was the perfect model for testing. If you are curious, <a href="https://www.tiagohenriques.dev/static/images/blog/image-background-remover-cli/simba.webp">here is</a> a before and after comparison!</p>
</blockquote>
<h2><a href="https://www.polpiella.dev/safari-extensions-swiftui">🧩 How to build a Safari extension with SwiftUI</a></h2>
<p>The latest version of <a href="https://www.getqreate.app/">QReate</a> features a fully redesigned <strong>Safari extension</strong> entirely built with <strong>SwiftUI</strong>.</p>
<p>Since there weren't many resources available on the topic, <a href="https://x.com/polpielladev">Pol</a> decided to write a blog post sharing his experience.
This is the guide you need to build your <strong>Safari extension</strong> so be sure to check it out if you are interested in it!</p>
<h2><a href="https://swifttoolkit.dev/posts/swift-parsing-package">🧱 Parsing Beyond JSON with swift-parsing</a></h2>
<p>Parsing goes beyond simply handling <strong>JSON</strong> from server <strong>API</strong> calls — it is about transforming <strong>unstructured</strong> data into <strong>structured</strong> formats.</p>
<p>In <a href="https://x.com/alexito4">Alejandro's</a> latest article on <a href="https://x.com/SwiftToolkit">Swift Toolkit</a>, he explores the depths of parsing and demonstrates its power, especially with a library like <a href="https://github.com/pointfreeco/swift-parsing">swift-parsing</a>.
If you are looking to refine your tools or dive deeper into parsing as a solution, I highly recommend giving this article a read to discover how versatile and impactful parsing can truly be!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>AI</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/refs/heads/main/issues/16.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[👀 Generate preview images for blog articles with SwiftUI and GitHub Actions 🖼]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue15</link>
            <guid>15</guid>
            <pubDate>Thu, 19 Sep 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Sharing links to your blog on social media looks much better with well-designed previews (e.g., on Twitter). These previews can be set up in various ways, often involving custom images for each post.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>15th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p><strong>Sharing links</strong> to your blog on social media looks much better with well-designed previews (e.g., on Twitter).
These previews can be set up in various ways, often involving custom images for each post.</p>
<p>I wasn't happy with how my newsletter posts were displayed on <strong>Twitter</strong>.
They appeared plain, lacking any image preview — just a dull, grey square.
Honestly, it didn't look appealing at all. Pretty disappointing, right 😑?</p>
<p>&lt;StaticHalfWidthImage
src=&quot;issues/issue15/tweet_with_no_preview.webp&quot;
alt=&quot;A tweet from me with no preview.&quot;
link=&quot;https://x.com/tiagodhenriques/status/1824455871381864712&quot;
caption=&quot;iOS Coffee Break Newsletter issue #11 tweet with no preview image&quot;
/&gt;</p>
<p>Some websites generate preview images either by using a predefined template or by creating them programmatically.
Here is an example by <a href="https://x.com/twannl">Antoine</a> where a preview is either based on a set template or dynamically generated through code. This is what I wanted to achieve!</p>
<p>&lt;StaticHalfWidthImage
src=&quot;issues/issue15/swiftlee-tweet.webp&quot;
alt=&quot;Swift Lee tweet.&quot;
link=&quot;https://x.com/twannl/status/1669629139609944064&quot;
caption=&quot;Antoine tweet displaying a custom preview image&quot;
/&gt;</p>
<p>I realized I needed to get my hands dirty, so I created an automated system using <strong>SwiftUI</strong> and <strong>GitHub Actions</strong> to generate custom preview images for my weekly issues 🖼.
This setup not only saves time but also guarantees that each post has a unique, polished look when shared on social media.</p>
<p>So if you are looking to add a personal touch to your blog articles, I recommend checking out the <a href="https://www.tiagohenriques.dev/blog/generate-issue-preview-images-with-swiftui-and-github-actions">article</a> I wrote on this topic.
It walks you through the entire process step by step!</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.manu.show/2024-09-15-toolset-team/">🏆 Day to Day Starting 11: The ToolSet Team to win championships</a></h2>
<p><a href="https://x.com/manuherrera1">Manu</a> has returned to writing and recently published one of the most unique articles I have come across in a while.
If you are into football, you will definitely enjoy it.
<strong>Manu</strong> creatively picks his own starting 11, featuring productivity tools that have made a significant impact on his workflow, efficiency, and daily life.</p>
<h2><a href="https://codingwithvera.com/using-charactirization-tests/?ref=coding-with-vera-newsletter">👴 Using Characterization Tests When Working With Legacy Code</a></h2>
<p>Every software engineer encounters <strong>legacy code</strong> at some point.
Being able to navigate various coding environments, particularly legacy ones, is crucial.</p>
<p><a href="https://x.com/CodingWithVera">Vera</a> shares insights from Michael C. Feathers' book <em>Working Effectively with Legacy Code</em>, emphasizing the importance of a concept called <strong>characterization tests</strong>.
By using these tests, you ensure that the existing code behaves as expected, which improves its readability for others and maintains consistency in future updates.</p>
<blockquote>
<p>P.S. Great job with the artistic touch, Vera!</p>
</blockquote>
<h2><a href="https://swifttoolkit.dev/posts/terminal-colors">🎨 Understanding Colors and Styles in Terminal Output</a></h2>
<p>When working with command line tools, visual design often takes a back seat, and most tools appear uniform and lack styling.
However, that doesn't have to be the case!</p>
<p>In this post, <a href="https://x.com/SwiftToolkit">Natan</a> breaks down how you can enhance the appearance of your <strong>Swift</strong> executables by using <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI Escape Codes</a>.
He provides a comprehensive guide on how to apply these codes to strings, allowing you to introduce styles like colors and formatting, giving your CLI tools a more polished and personalized look.</p>
<h2><a href="https://www.polpiella.dev/binding-navigation">🚚 How to pass Bindings to views in SwiftUI's NavigationDestination modifier</a></h2>
<p>In <strong>SwiftUI</strong>, it is typical to display a list where users can navigate to a detailed view after selecting an item.
However, it may not be immediately obvious how to use bindings when working with <code>NavigationLinks</code> and the <code>.navigationDestination</code> modifier.</p>
<p>In this article, <a href="https://x.com/polpielladev">Pol</a> outlines two straightforward methods that make passing a binding to the detail view seamless, offering a clear solution to this common challenge.</p>
<h2><a href="https://pfandrade.me/blog/swift-build-times-and-module-verification/">⌛ Swift Build Times and Module Verification...</a></h2>
<p><a href="https://x.com/pfandrade_">Paulo</a> shared an useful tip for those building <strong>Swift</strong> frameworks to significantly reduce build times.
By setting <code>ENABLE_MODULE_VERIFIER</code> to <code>FALSE</code>, his clean build times dropped from 3.5 minutes to just 52 seconds 😱.</p>
<p>If you are working with <strong>Swift</strong> frameworks and using <strong>Xcode 16 betas</strong>, it is highly recommended to apply this build setting change for <strong>debug</strong> builds and <strong>build with timing summaries</strong> periodically for optimization insights.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>GitHub Actions</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/main/issues/15.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🕵️ How to publish your app to the App Store 🚀]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue14</link>
            <guid>14</guid>
            <pubDate>Fri, 06 Sep 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Launching an app for the first time or after a long break can be breathtaking. While submitting an app to the App Store isn't as straightforward as pressing a button, it is more manageable than it seems. The first time I went through this, I was overwhelmed by all the information I was getting.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>14th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>The <strong>August Giveaway</strong> 🏖️ has officially wrapped up, and I had a fantastic time organizing it!
I would like to extend a big thank you 🙏 to everyone who participated and a huge congratulations to the winners 🎉.</p>
<p>I hope the books bring you lots of <strong>value</strong> — use them to create exciting new applications, and don't forget to share your work with the community!</p>
<p>&lt;StaticTweet id=&quot;1830149229353803816&quot; /&gt;</p>
<p>This week, I decided to set up a <strong>guide on how to publish your app to the App Store</strong>.</p>
<p><strong>Launching</strong> an <strong>app</strong> for the first time or after a long break can be <strong>breathtaking</strong>. While submitting an app to the <strong>App Store</strong> isn't as straightforward as pressing a button, it is more manageable than it seems.
The first time I went through this, I was overwhelmed by all the information I was getting.</p>
<p>Assuming you are in the <a href="https://developer.apple.com/programs/">Apple Developer Program</a>, your app follows <strong>Apple's</strong> <a href="https://developer.apple.com/app-store/review/guidelines/">App Review</a> and <a href="https://developer.apple.com/design/human-interface-guidelines">Human Interface</a> guidelines, declares its <strong>APIs</strong> usage in the <a href="https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api">Privacy Manifest</a> file, and you are ready to ship, here is what to do in order to distribute your app for beta testing or to go live in the <strong>App Store</strong>.</p>
<blockquote>
<p>The Apple Developer Program membership pricing starts at $99 per year, and it gives you access to other exclusive Apple developer tools and services. If you are looking for a good resource to create your Privacy Manifest file for you, <a href="https://www.privacymanifest.dev/">here</a> is one by <a href="https://x.com/DonnyWals">Donny Wals</a>.</p>
</blockquote>
<h3>1. Code signing: Setting up an iOS distribution provisioning profile and certificate</h3>
<p>The <strong>development provisioning profile</strong> and <strong>certificate</strong> you have been using are limited to specific devices. For broader distribution to beta testers or the <strong>App Store</strong>, you will need separate <strong>distribution credentials</strong>.</p>
<p>To create these, visit your <a href="https://developer.apple.com/">Apple Developer</a> account and navigate to <em>&quot;Certificates, Identifiers &amp; Profiles&quot;</em>. Generate a <strong>Distribution Certificate</strong> for either <strong>App Store</strong> or <strong>Ad Hoc</strong> use, install it in your Mac's Keychain, then create and download a matching <strong>Distribution Provisioning Profile</strong>.
Finally, integrate these into <strong>Xcode</strong> for code signing.</p>
<blockquote>
<p>Initially, this process may feel tedious, but it's essential for secure app distribution. Trust me, I have been there!</p>
</blockquote>
<h3>2. Create an App Store Connect record for your App</h3>
<p><a href="https://appstoreconnect.apple.com/">App Store Connect</a> is where <strong>Apple Developer Program</strong> members manage app submissions, updates, and post-launch features.</p>
<p>To create a new app record, log into <strong>App Store Connect</strong>, go to <em>&quot;My Apps&quot;</em>, and click <em>&quot;New App&quot;</em>. Enter key details like the app's <strong>name</strong>, <strong>primary language</strong>, <strong>bundle ID</strong>, and <strong>SKU</strong>.
You will also assign user access permissions for managing the app. Once completed, this record allows you to upload your app build, add metadata, and prepare it for submission to the <strong>App Store</strong>.</p>
<h3>3. Archive and upload your app with Xcode</h3>
<p>To <strong>archive</strong> and <strong>upload</strong> your app in <strong>Xcode</strong>, ensure you are using a <strong>production</strong> scheme.</p>
<ul>
<li>Go to <em>&quot;Product&quot;</em> &gt; <em>&quot;Archive&quot;</em> to package your app. Once the archive is created, the <strong>Organizer</strong> window will open.</li>
<li>Select the <strong>archive</strong> and click <em>&quot;Distribute App&quot;</em>. Opt for <em>&quot;App Store Connect&quot;</em> and follow the prompts to validate, sign, and <strong>upload</strong> your app.</li>
</ul>
<p>After uploading, your build will be accessible in <strong>App Store Connect</strong>, ready for further processing and submission.</p>
<h3>4. Set up your app's metadata and details in App Store Connect</h3>
<p>In <strong>App Store Connect</strong>, under the <em>&quot;App Store&quot;</em> tab, you will find the <em>&quot;App Information&quot;</em> page where you can add <strong>languages</strong>, <strong>categories</strong>, and your app's <strong>privacy policy</strong> URL.
Configure <strong>pricing</strong>, upload <strong>screenshots</strong> (in JPEG or PNG format), and provide essential details like your app's <strong>description</strong>, <strong>keywords</strong>, <strong>support</strong> and <strong>marketing</strong> URL.</p>
<blockquote>
<p>Your app's description and keywords are critical so make sure you optimize them for discovery. You might take a look at this <a href="https://www.rudrank.com/exploring-indie-life-learning-aso-app-store-optimization-for-keywords/">article</a> by <a href="https://x.com/rudrankriyam">Rudrank</a> where he learns ASO (App Store Optimization) for keywords.</p>
</blockquote>
<p>In the <em>&quot;General App Information&quot;</em> section, upload your app's <strong>icon</strong> (1024px x 1024px), set the <strong>version number</strong>, and include <strong>copyright</strong> and <strong>contact details</strong>.
Save your progress, and you will be ready to submit for review.</p>
<blockquote>
<p>If you are like me and feel challenged by design work, creating an app icon might seem intimidating. I recommend exploring the introductory <a href="https://www.sketch.com/guides/">Sketch guides and courses</a> to get started. That is how I managed to design the <a href="https://www.padeltime.app/og-image.png">icon</a> for my app Padel Time. Sketch is also my number one tool to create my app screenshots.</p>
</blockquote>
<h3>5. Submit your app for review</h3>
<p>To submit your app for <strong>review</strong>, go to the <em>&quot;Build&quot;</em> section in your app's <strong>App Store Connect</strong> record and click <em>&quot;Select a build before you submit your app&quot;</em>.
Pick the build you uploaded through <strong>Xcode</strong>, then click Done and Save. Next, select <em>&quot;Submit for Review&quot;</em>.
You will need to complete the questions on Export Compliance, Content Rights, and the Advertising Identifier.
Once done, click Submit. Your app is now in the review queue for <strong>Apple's</strong> approval process.</p>
<blockquote>
<p>Typically, approval takes one to three days, and it may take up to 24 hours for your app to be available in the App Store afterward. You will receive email updates throughout the process.</p>
</blockquote>
<p>If your app is approved, congratulations 🥳! You are now on the <strong>App Store</strong>. You can view downloads, sales, ratings, and reviews directly in <strong>App Store Connect</strong>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>App Store</category>
        </item>
        <item>
            <title><![CDATA[🙋‍♂️ How I created a Swift CLI tool to select the winners for the August Giveaway 🏖️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue13</link>
            <guid>13</guid>
            <pubDate>Fri, 30 Aug 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Earlier this month, I announced a giveaway for all newsletter subscribers, offering a chance to win one of three copies of SwiftUI Picture Books by Big Mountain Studio. When I began learning SwiftUI, the SwiftUI Views Mastery book was instrumental in helping me quickly grasp the framework and best practices.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>13th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Earlier this month, I announced a <strong>giveaway</strong> for all newsletter subscribers, offering a chance to win one of three copies of <strong>SwiftUI Picture Books</strong> by <a href="https://x.com/BigMtnStudio">Big Mountain Studio</a>. When I began learning <strong>SwiftUI</strong>, the <a href="https://www.bigmountainstudio.com/views/2f6cl?coupon=IOSCOFFEEBREAK">SwiftUI Views Mastery</a> book was instrumental in helping me quickly grasp the framework and best practices.</p>
<p>A huge thanks 🙏 to <a href="https://x.com/BigMtnStudio">Mark</a> for generously providing these copies and for offering valuable resources to the iOS community.</p>
<p>&lt;StaticTweet id=&quot;1823786925989535927&quot; /&gt;</p>
<p>To select the winners of the newsletter's <strong>August Giveaway</strong> 🏖️, I built a <strong>CLI</strong> tool in <strong>Swift</strong> called <strong>giveawaypicker</strong>.
This tool pulls my subscriber list from the database, randomly selects three emails, and displays them.
In this issue, I explain how to use <strong>GitHub Actions</strong> to automate the process of building the executables for <strong>macOS</strong> and publishing them as a <strong>GitHub Release</strong>.</p>
<p>The issue is divided into two parts: the first covers the scripts for <strong>building and bundling the binaries</strong>, and the second details a <strong>GitHub Actions</strong> workflow that executes these scripts.</p>
<blockquote>
<p>I chose not to delve into the code that retrieves my subscribers list from the database and selects three random emails since it's essentially just a GET request followed by the selection of three random items. However, if you are interested, here is the <a href="https://github.com/henriquestiagoo/giveaway-picker/blob/main/Sources/GiveawayPicker.swift">code</a>.</p>
</blockquote>
<h3>Script: Build for macOS</h3>
<p>After I have written all the <a href="https://github.com/henriquestiagoo/giveaway-picker/tree/main/Sources">code</a>, I created a directory named <code>scripts</code> and inside it, created a script named <code>build-macos.sh</code>. These were the commands to do so:</p>
<pre><code class="language-sh">mkdir scripts
touch build-macos.sh
</code></pre>
<p>Then, I added the following lines to the file.</p>
<pre><code class="language-sh">#!/bin/sh

set -e

swift build -c release --product giveawaypicker
BUILD_PATH=$(swift build -c release --product giveawaypicker --show-bin-path)
echo -e &quot;\n\nBuild at ${BUILD_PATH}&quot;

DESTINATION=&quot;builds/giveawaypicker-macos&quot;
if [ ! -d &quot;builds&quot; ]; then
    mkdir &quot;builds&quot;
fi

cp &quot;$BUILD_PATH/giveawaypicker&quot; &quot;$DESTINATION&quot;
echo &quot;Copied binary to $DESTINATION&quot;
</code></pre>
<p>The script compiles the single executable target in release mode.
It then uses the <code>--show-bin-path</code> argument to determine the location of the generated binary.
Next, it defines a destination path for the executable, creates the necessary builds folder if it doesn't already exist, and finally, uses the <code>cp</code> command to copy the binary to that destination.</p>
<p>Before you test the script locally, ensure it has executable permissions by setting them up:</p>
<pre><code class="language-sh">chmod +x scripts/build-macos.sh
</code></pre>
<p>Now, I can run it to check it builds and stores the binary in the correct location. This is the command to do so:</p>
<pre><code class="language-sh">./scripts/build-macos.sh
</code></pre>
<p>After running the command, I can check that the binary was created at the specified location: <code>/builds/giveawaypicker-macos</code>.</p>
<h2>Writing the GitHub Actions workflow</h2>
<p>Next, I needed a <strong>GitHub</strong> workflow with the following characteristics:</p>
<ul>
<li>Be triggered when creating a new release in your repository.</li>
<li>Execute the previous script in a macOS machine.</li>
<li>Upload the build to the release page.</li>
</ul>
<p>I first started by creating a workflow file in the <code>.github/workflows</code> folder:</p>
<pre><code class="language-sh">mkdir -p .github/workflows
touch .github/workflows/build-and-release.yml
</code></pre>
<p>Then, I added the following lines to the file.</p>
<pre><code class="language-sh">on:
  release:
    types: [published]

name: Build Release Artifacts
jobs:
  build-macos:
    name: Build macOS Executable
    runs-on: macos-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Build macOS binary
        run: scripts/build-macos.sh
      - name: 'Upload macOS Build Artifact'
        uses: actions/upload-artifact@v4
        with:
          name: giveawaypicker-macos
          path: builds/giveawaypicker-macos

  upload:
    name: Upload release artifacts
    runs-on: ubuntu-latest
    needs: [build-macos]
    steps:
      - uses: actions/download-artifact@v4
        with:
          path: .
      - name: List downloaded files
        run: ls -R
      - name: Upload to Release
        uses: softprops/action-gh-release@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          tag_name: ${{ github.event.release.name }}
          files: ./*/*
          fail_on_unmatched_files: true
</code></pre>
<p>To wrap the workflow, I began by setting up a job to build the macOS binary.
I used the <code>checkout</code> action to clone the repository onto the machine, followed by running the <code>build-macos.sh</code> script.
Finally, I applied the <code>upload-artifact</code> action to store the resulting binary within the workflow.</p>
<h2>Publishing a Release</h2>
<p>After I commited the scripts and workflow file and pushed the changes, I could then create a new <strong>release</strong>.
To do this, I went to the <strong>GitHub</strong> repository, clicked on <strong>&quot;Releases&quot;</strong> on the right side, and selected <strong>&quot;Create a new release&quot;</strong>.
From there, generated a new tag, added a title and description for the release.</p>
<p>After some time, the binary appears as an asset in the release!</p>
<p>&lt;StaticImage
src=&quot;/issues/issue13/giveawaypicker_release.webp&quot;
alt=&quot;Giveaway Picker v0.1.0 binary in the release assets.&quot;
link=&quot;/issues/issue13/giveawaypicker_release.webp&quot;
caption=&quot;Giveaway Picker v0.1.0 binary in the release assets.&quot;
/&gt;</p>
<p>Feel free to clone the <a href="https://github.com/henriquestiagoo/giveaway-picker">repository</a>, use SPM to build it and run the executable:</p>
<pre><code class="language-sh">swift run giveawaypicker -i &lt;supabase_reference_id&gt; -k &lt;supabase_key&gt;
</code></pre>
<p>At the end of the month, I will run the tool and announce the winners 🎉. I will reach out to the winners via email, so stay tuned!</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics submitted by the community. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://blog.eliperkins.com/great-release-notes">✍️ Writing great release notes doesn’t need to be hard</a></h2>
<p>We have all resorted to the classic <strong>&quot;Bug fixes and performance improvements&quot;</strong> in our app release notes.
However, it is crucial to make our release notes <strong>clear</strong> and <strong>consistent</strong>!
They should reflect a unified tone, be grammatically correct, prioritize changes based on user impact, and guide users on any necessary follow-up actions.</p>
<p>I highly recommend checking out <a href="https://x.com/_eliperkins">Eli's</a> article for helpful tips on improving your release notes and better informing your users about what's been fixed or enhanced.</p>
<h2><a href="https://useyourloaf.com/blog/swiftui-previewable-macro/">🔎 SwiftUI Previewable Macro</a></h2>
<p><strong>Apple</strong> introduced the <a href="https://developer.apple.com/documentation/SwiftUI/Previewable()">Previewable</a> macro in <strong>iOS 18</strong>.
This macro simplifies and speeds up the process of previewing views by automatically creating the boilerplate wrapper view with State bindings.</p>
<p>In this article from <a href="https://x.com/kharrison">Use your Loaf</a>, you can learn how to replace that boilerplate wrapper code with the <code>Previewable</code> macro.</p>
<h2><a href="https://www.pointfree.co/blog/posts/151-cross-platform-swift-building-a-swift-app-for-the-browser">🐙 Cross-Platform Swift: Building a Swift app for the browser</a></h2>
<p>Point Free's latest series focuses on <a href="https://www.pointfree.co/collections/cross-platform-swift">cross-platform Swift</a>, starting with a basic guide on running a simple <strong>Swift</strong> app in a browser.
This week, they released a blog post detailing how they recreated their counter feature in <strong>Swift</strong>, running it in the browser using <a href="https://en.wikipedia.org/wiki/WebAssembly">WebAssembly</a>.</p>
<p><strong>WebAssembly</strong> is a binary format that allows running languages like <strong>Swift</strong> directly in the browser, not just <strong>JavaScript</strong>.
For more details, I highly suggest you to check out their article and watch the free episodes in the series.</p>
<h2><a href="https://swifttoolkit.dev/posts/dc-andrew-barba">👨‍💻 Dev Conversations: Andrew Barba</a></h2>
<p><a href="https://x.com/natanrolnik">Natan</a> has introduced a new series on <a href="https://swifttoolkit.dev/">SwiftToolkit</a> titled <em>&quot;Dev Conversations&quot;</em> featuring brief interviews with developers focused on the <strong>Swift</strong> server and tooling ecosystem.
This month, he spoke with <a href="https://x.com/andrew_barba">Andrew</a> about his early career, transitioning from <strong>iOS</strong> development to backend work, and the recent release of <a href="https://github.com/swift-cloud/swift-cloud">Swift Cloud</a>.</p>
<p>If you are interested in the <strong>Swift</strong> ecosystem, this series is worth following for valuable insights and perspectives from other developers.</p>
<h2>Reference</h2>
<ul>
<li><a href="https://swifttoolkit.dev/posts/releasing-with-gh-actions">Releasing Swift Binaries with GitHub Actions</a></li>
<li><a href="https://supabase.com/docs/reference/swift/introduction">Supabase Swift Client Library</a></li>
</ul>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>CLI</category>
        </item>
        <item>
            <title><![CDATA[🧰 My set of must-have tools for Apple platforms developers 👨‍💻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue12</link>
            <guid>12</guid>
            <pubDate>Fri, 23 Aug 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[As an Apple platforms developer's, your journey involves creating apps for Apple devices like iPhone, Apple Watch, Apple TV, and more. Developers use specialized tools to design, build, test, and deploy these apps. The right combination of these resources helps companies deliver high-quality apps that function smoothly across the Apple ecosystem.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>12th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>As an <strong>Apple</strong> platforms developer's, your journey involves creating apps for <strong>Apple</strong> devices like iPhone, Apple Watch, Apple TV, and more.
Developers use specialized tools to design, build, test, and deploy these apps.
The right combination of these resources helps companies and individuals to deliver high-quality apps that function smoothly across the <strong>Apple</strong> ecosystem.</p>
<p>To help you with this process, here are my <strong>must-have</strong> set of <strong>tools</strong> that can benefit you as an <strong>Apple platforms developer</strong> divided by categories.</p>
<blockquote>
<p>The tools I have included in this issue aren’t sponsored in any way. Most are ones I personally rely on daily, while others are featured based on positive feedback from the community.</p>
</blockquote>
<h3>1. Integrated Development Environments (IDEs) and Editors</h3>
<p>To write code, we need an integrated development environment <strong>(IDE)</strong>.</p>
<p><a href="https://developer.apple.com/xcode/">Xcode</a> is usually the top choice because it is built by Apple and includes everything required for <strong>iOS, macOS, watchOS, and tvOS</strong> development.
It is the go-to tool for many developers, including me, since it is optimized for Apple's platforms and seamlessly integrates with <strong>Cocoa</strong> and <strong>Cocoa Touch</strong> frameworks.</p>
<p>However, you can also explore alternatives like <a href="https://www.jetbrains.com/objc/">AppCode</a> and <a href="https://code.visualstudio.com/">VSCode</a>.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue12/xcode.webp&quot;
alt=&quot;Xcode for Padel Time.&quot;
link=&quot;/issues/issue12/xcode.webp&quot;
caption=&quot;Xcode for Padel Time.&quot;
/&gt;</p>
<p><em>Xcode is my only choice for writing code. Yeah, I know that sometimes it does crash, but it is the best IDE for designing, coding, testing and debugging apps.</em></p>
<h3>2. Testing and Debugging</h3>
<p>There are several <strong>testing and debugging</strong> tools available to help developers release high-quality <strong>iOS</strong> apps with minimal bugs and errors.</p>
<p><a href="https://help.apple.com/instruments/mac/current/">Instruments</a>, integrated within <strong>Xcode</strong>, is a performance analyzer that helps you profile apps for various <strong>Apple</strong> platforms, allowing early identification of issues during development.</p>
<p><a href="https://proxyman.io/">Proxyman</a> is a modern, native and web debugging proxy for macOS, letting you inspect <strong>HTTP</strong> and <strong>HTTPS</strong> traffic between your device and the internet.
Alternatives include <a href="https://www.charlesproxy.com/">Charles Proxy</a> and <a href="https://www.postman.com/">Postman</a>, which serve similar functions for traffic inspection and debugging.</p>
<h3>3. Automation, Continuous Integration and Continuous Delivery (CI/CD)</h3>
<p><strong>CI/CD</strong> tools greatly enhance deployment efficiency for <strong>iOS</strong> developers by automating repetitive tasks like releases, code signing, and screenshot generation.</p>
<p><a href="https://fastlane.tools/">Fastlane</a>, an open-source platform, streamlines deployment processes by automating everything from taking screenshots to submitting apps to the <strong>App Store</strong>.
It integrates smoothly with <strong>CI</strong> services.
Popular alternatives include <a href="https://www.jenkins.io/">Jenkins</a> and <a href="https://codemagic.io/start/">Codemagic</a>.</p>
<p><a href="https://developer.apple.com/xcode-cloud/">Xcode Cloud</a> offers a built-in <strong>Apple</strong> solution for continuous integration and delivery, providing tools for app building, automated testing, and feedback management.
<a href="https://www.jetbrains.com/teamcity/">TeamCity</a> is another <strong>CI/CD</strong> option offering robust features for development workflows.</p>
<blockquote>
<p>An Apple Developer Program membership includes 25 compute hours per month of Xcode Cloud usage which should be enough to get your app up and running.</p>
</blockquote>
<p>&lt;StaticImage
src=&quot;/issues/issue12/xcode_cloud.webp&quot;
alt=&quot;Xcode Cloud workflows for Padel Time.&quot;
link=&quot;/issues/issue12/xcode_cloud.webp&quot;
caption=&quot;Xcode Cloud workflows for Padel Time.&quot;
/&gt;</p>
<h3>4. User Testing and Distribution</h3>
<p>After crafting your amazing app, gathering feedback and identifying potential crashes through user testing is essential.</p>
<p><a href="https://developer.apple.com/testflight/">TestFlight</a> by <strong>Apple</strong> allows you to invite up to <code>10,000</code> testers via email or a shared link, making it easy to gather feedback before launching on the <strong>App Store</strong>. Testers can provide insights, including screenshots or crash details, directly from the app.</p>
<p>Other options include <a href="https://firebase.google.com/docs/app-distribution">Firebase App Distribution</a> and <a href="https://testfairy.com/">TestFairy</a>, which offer similar beta testing solutions but are not first party solutions to developers.</p>
<h3>5. Design and Prototype</h3>
<p><strong>Design and prototyping</strong> tools are essential for <strong>iOS</strong> developers in building the <strong>UX/UI</strong> of their applications.</p>
<p><a href="https://www.sketch.com/">Sketch</a> is a leading tool for creating and editing vector graphics.
I often use it myself for designing user interfaces for my mobile apps and websites.</p>
<p>&lt;StaticImage
src=&quot;/issues/issue12/sketch_padeltime.webp&quot;
alt=&quot;iPhone App Store screenshots for Padel Time 1.2.0.&quot;
link=&quot;/issues/issue12/sketch_padeltime.webp&quot;
caption=&quot;iPhone App Store screenshots for Padel Time 1.2.0.&quot;
/&gt;</p>
<p>Its collaboration features, like <strong>Sketch Cloud</strong> for syncing and sharing, make teamwork easier.</p>
<p>Other popular options include <a href="https://adobexdplatform.com/">Adobe XD</a>, which has received positive community feedback, though I haven't personally used it. You can also explore <strong>AI-driven</strong> design assistance tools like <strong>ChatGPT</strong> or <strong>Claude 3.5 Sonnet</strong> for creative input.</p>
<blockquote>
<p>If you are like me and feel challenged by design work, creating an app icon might seem intimidating. I recommend exploring the introductory <a href="https://www.sketch.com/guides/">Sketch guides and courses</a> to get started. That is how I managed to design the <a href="https://www.padeltime.app/og-image.png">icon</a> for my app Padel Time. Sketch is also my number one tool to create my app screenshots.</p>
</blockquote>
<h3>6. Other Developer tools</h3>
<p><a href="https://brew.sh/">Homebrew</a> is a free, open-source package manager designed to streamline software installation on <strong>macOS</strong>.
Once installed, <strong>Homebrew</strong> allows users to easily download and set up software from its large repository, which includes thousands of packages like <strong>Fastlane</strong>.</p>
<blockquote>
<p>If you are not aware, you can contribute and add new software to the Homebrew repository. For more intructions, check out their <a href="https://docs.brew.sh/Adding-Software-to-Homebrew">official guide</a>.</p>
</blockquote>
<p><a href="https://www.sourcetreeapp.com/">SourceTree</a> is a <strong>Git</strong> client with a graphical interface, making it easier to manage code repositories without relying on command-line tools.
It provides a smooth way to interact with your projects by enabling you to perform tasks like cloning, committing, and managing branches visually.
If you prefer alternatives, you can try <a href="https://git-fork.com/">Fork</a> (which is paid) or <strong>Xcode</strong>, which has built-in <strong>Git</strong> source control integration.</p>
<blockquote>
<p>I usually stick with Xcode and its Git support for basic tasks but switch to SourceTree when handling more complex merge conflicts.</p>
</blockquote>
<p><a href="https://www.docker.com/">Docker</a> is a tool designed for running applications in containers, which offer similar isolation and security as virtual machines but are more lightweight because they share the host system's <strong>OS</strong>.
With <strong>Docker</strong>, you can easily deploy and scale applications across different environments while ensuring consistency in how your code runs.</p>
<blockquote>
<p>If you work with Server-Side Swift, Docker is especially beneficial since many servers operate on Linux, making it a reliable solution for testing and deploying your applications in a production-like environment.</p>
</blockquote>
<p>Uff, that was a lot! Hope that you find here <strong>tools</strong> that can make your life easier as an <strong>Apple developer</strong>. Now it's time to dive into some <strong>iOS</strong> development topics. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://codingwithvera.com/how-i-switched-from-qa-to-senior-ios-developer/">🧗‍♀️ How I switched from QA to Senior iOS Developer</a></h2>
<p><strong>Trust in your potential</strong> and don't let others define your limits, and this extends beyond just programming.
<a href="https://x.com/CodingWithVera">Vera's</a> article is a great source of inspiration, encouraging everyone to chase their dreams, stand up for what they want, and realize their full potential.</p>
<p>Start by taking small steps in a secure environment, like at home, where it is safe to fail and learn.
From there, gather the resources to move forward.
Ultimately, your growth and success are in your own hands 👐!</p>
<h2><a href="https://darrylbayliss.net/getting-setup-with-xcode-cloud/">☁️ Getting started with Xcode Cloud</a></h2>
<p><a href="https://developer.apple.com/xcode-cloud/">Xcode Cloud</a> offers an easy-to-use <strong>CI/CD</strong> platform specifically designed for <strong>Apple</strong> applications.
If you are new to <strong>Xcode Cloud</strong>, I highly suggest exploring <a href="https://x.com/darryl_bayliss">Darryl's</a> detailed guide, which walks you through setting it up, creating a build workflow and configuring post-build actions to receive notifications about your workflow results.
It is a great resource to help you smoothly get started with <strong>Xcode Cloud</strong> and make the most of its features.</p>
<h2><a href="https://brightinventions.pl/blog/ios-testflight-github-actions-fastlane-match/">✅ Upload iOS apps to TestFlight with GitHub actions and Fastlane</a></h2>
<p>The third and final part of a tutorial series on creating an <strong>iOS CI/CD pipeline</strong> is now available!
In the earlier parts, <strong>Artur</strong> from <a href="https://x.com/BrightDevs">Bright Inventions</a> covered building and testing an app locally using <strong>Fastlane</strong>, and then setting up <strong>GitHub Actions</strong> for these tasks.</p>
<p>In this part, <strong>Artur</strong> demonstrates how to upload an app to <strong>TestFlight</strong> using <strong>GitHub Actions</strong> alongside the <a href="https://docs.fastlane.tools/actions/match/">Fastlane Match</a> tool.
You will also learn how <strong>Fastlane Match</strong> works and how to securely pass sensitive data like API keys and tokens in <strong>GitHub</strong> actions workflows without exposing them in the codebase.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Tools</category>
        </item>
        <item>
            <title><![CDATA[🧑‍💻 How I keep myself motivated and how to build a personal brand 🏋️‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue11</link>
            <guid>11</guid>
            <pubDate>Fri, 16 Aug 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Running a newsletter is challenging but immensely rewarding. It enhances your knowledge, builds connections, and allows you to help others. The iOS Coffee Break Newsletter has been live for almost three months, and it is one of the best career decisions I have made despite balancing it with my full-time job.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>11th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>Running a <strong>newsletter</strong> is challenging but immensely rewarding. It enhances your knowledge, builds connections, and allows you to help others.
The <strong>iOS Coffee Break Newsletter</strong> has been live for almost <strong>three months</strong>, and it is one of the <strong>best career decisions</strong> I have made despite balancing it with my full-time job.</p>
<p>Here are some strategies that keep me motivated in my side project. These points are what work best for me, but I hope you can relate to some of them.</p>
<h3>1. Dedicate daily time to your side project</h3>
<p>For me, I dedicate a small part of my day to <strong>staying updated</strong> with the latest <strong>community</strong> news.
I usually <strong>take notes</strong> or <strong>bookmark articles</strong> that I might want to feature in that week's issue.
At the end of the week, I review everything and pick what is most relevant at the time.
If your side project is focused on coding, it is helpful to set aside a short amount of time each day to work on improvements, build features, or fix bugs.</p>
<h3>2. Engage in activities outside work</h3>
<p>For me, <strong>staying active</strong> is key! Exercising helps me unwind after a long day, and it is also great for boosting brain function.
I have been playing <strong>Padel</strong> with colleagues from work once or twice a week and hitting the <strong>gym</strong> 2-3 times a week.
If sports aren't your thing, find another activity that brings you joy — whether it is playing an instrument, learning a new language, cooking, meditating, or something else entirely. The important part is doing what makes you feel good.</p>
<h3>3. Set clear long-term goals for your project</h3>
<p>Where do you want to be <strong>six months from now</strong>? It is essential to have a <strong>clear vision</strong> to effectively plan the steps needed to get there.
For example, I am aiming for <strong>500 subscribers</strong> by this year's end, which requires consistent effort.
Whether that is gathering feedback or analyzing metrics to see what content resonates most with your audience, success requires ongoing dedication and strategic planning.</p>
<h3>4. Celebrate every win, no matter how small</h3>
<p>Even <strong>minor achievements</strong> can be <strong>meaningful</strong>! For example, I was thrilled when I hit my first <strong>50 followers</strong> and received the initial <strong>community submissions</strong>.
Share these milestones with others — whether through <strong>X</strong> or other platforms — connect with people, and track your growth along the way.</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.youtube.com/watch?v=mDEXNLUKesw&amp;list=PLVKQDFwOy1XZmO842JG6hozdZNdqhDYuS&amp;index=13&amp;t=299s">🏋️‍♂️ Building a personal brand to elevate your iOS career</a></h2>
<p><a href="https://x.com/iOSKonf">iOSKonf</a> recently uploaded this year’s talks on <a href="https://www.youtube.com/playlist?list=PLVKQDFwOy1XZmO842JG6hozdZNdqhDYuS">YouTube</a>, and one by <a href="https://x.com/rudrankriyam">Rudrank</a> grabbed my attention.
He discussed his journey to building a personal brand and becoming indie, offering valuable tips for advancing your <strong>iOS</strong> career and gaining visibility in the <strong>iOS</strong> community.</p>
<p>One key takeaway was a <strong>Rudrank's</strong> quote: <em>&quot;The best possible marketing you can do is to add value to other people's lives.&quot;</em>
This aligns with why I created this newsletter — to <strong>share knowledge</strong> and <strong>build connections</strong> by contributing to the community through <strong>content</strong> and <strong>resources</strong>.</p>
<h2><a href="https://www.createwithswift.com/removing-image-background-using-the-vision-framework/">✂️ Removing image background using the Vision framework</a></h2>
<p>This week, <a href="https://x.com/matteoaltobello">Matteo</a> from <a href="https://x.com/createwithswift">Create with Swift</a> shared an insightful article on using the <code>VNGenerateForegroundInstanceMaskRequest</code> API, part of the <a href="https://developer.apple.com/documentation/vision">Vision framework</a>, to simplify background removal in images.
I have often found myself struggling with design tools for this task, so this <strong>API</strong> is a game-changer.</p>
<p>The process involves three main steps: <strong>generating a mask from the image</strong>, <strong>applying that mask to isolate the subject</strong> and then <strong>converting the result into a displayable format in the UI</strong>.
This approach streamlines what was once a complex task into a more manageable process.</p>
<h2><a href="https://www.massicotte.org/step-by-step-network-request">⌛ Concurrency Step-by-Step: A Network Request</a></h2>
<p><a href="https://github.com/mattmassicotte">Matthew Massicotte</a>, an experienced <strong>Apple</strong> platforms developer, recently published an in-depth article on making network requests with SwiftUI.
He explores various techniques, diving deep into how network requests function while showcasing the power of <a href="https://developer.apple.com/documentation/swift/mainactor">MainActor</a> and its interaction with <strong>Swift concurrency</strong>.</p>
<p>The article also highlights how to effectively use the <code>nonisolated</code> keyword to manage actor isolation and prevent unwanted behavior.
<strong>Matthew’s</strong> insights are especially valuable for developers eager to master <strong>Swift concurrency</strong> and I really look forward to meet him at <a href="https://swiftleeds.co.uk/">Swift Leeds</a> and hopefully gain deeper insights into how <strong>Swift Concurrency</strong> works.</p>
<h2><a href="https://swifttoolkit.dev/posts/hello-swift-cloud">🤲 An initial hands-on with SwiftCloud</a></h2>
<p>This article by <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> offers an introductory guide to <a href="https://github.com/swift-cloud/swift-cloud">SwiftCloud</a>, showing you how to deploy two <strong>Lambda functions</strong> to <strong>AWS</strong> with live examples.
<a href="https://x.com/andrew_barba">Andrew Barba's</a> new open-source package handles the setup seamlessly—it builds the targets using <strong>SPM</strong>, uploads them, and manages resource creation if needed.
I have previously used <strong>SwiftCloud</strong> to deploy Swift apps on Vercel, so I am eager to test out this new integration with <strong>Lambda functions</strong>.
And the best part is that you can also use the WebServer component to deploy any existing Hummingbird or Vapor application!</p>
<h2><a href="https://x.com/polpielladev/status/1823676094895026227">🚀 Ship your indie apps in hours, not days!</a></h2>
<p>Last month, <a href="https://x.com/polpielladev">Pol</a> shared exciting news about transitioning fully into freelancing, indie app development, and content creation.
He is kicking off September with a new workshop titled <em>&quot;Ship your indie apps in hours, not days!&quot;</em>
The 3-hour session is packed with tips, tools, and <strong>CI/CD</strong> workflows.</p>
<p>I have been following <strong>Pol’s</strong> work for around a year, and his insights have helped me <strong>automate tasks</strong> and <strong>migrate our CI/CD pipelines</strong> to <a href="https://developer.apple.com/xcode-cloud/">Xcode Cloud</a>.
Be sure to mark your calendar for this event 🗓️!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[🤖 Releasing Swift binaries with GitHub actions and how Senior Devs fix problems 👴🏻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue10</link>
            <guid>10</guid>
            <pubDate>Fri, 09 Aug 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[This week, I was thrilled to hear about RevenueCat's hackathon, Ship-a-ton. The challenge is to launch an app on the App Store or Google Play Store, using the RevenueCat SDK for in-app purchase monetization.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>10th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.</p>
<p>This week, I was thrilled to hear about <a href="https://x.com/RevenueCat">RevenueCat's</a> hackathon, <a href="https://revenuecat-ship-a-ton.devpost.com/">Ship-a-ton</a>.
The challenge is to launch an app on the <strong>App Store</strong> or <strong>Google Play Store</strong>, using the <strong>RevenueCat SDK</strong> for in-app purchase monetization.
I am considering this as the perfect chance to finally bring an old app idea of mine to life and release it within <code>30 days</code>.
Let's see if that short timeline works out!</p>
<p>On a different note, <strong>Swift Leeds</strong> just revealed an exciting lineup of speakers. Which one are you most looking forward to hearing?</p>
<p>Now it's time to dive into some <strong>iOS</strong> development topics. Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://swifttoolkit.dev/posts/releasing-with-gh-actions">🤖 Releasing Swift Binaries with GitHub Actions</a></h2>
<p>Curious about how to automate the release process for <strong>Swift executables</strong> using <strong>GitHub Actions</strong> and <strong>GitHub Releases</strong>?</p>
<p>In recent weeks, <a href="https://x.com/natanrolnik">Natan</a>, the curator of <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> explored various methods for building <strong>Swift binaries</strong> across different operating systems and architectures.
This week, he takes it a step further, showing how to leverage <strong>GitHub Actions</strong> to automate the building of executables for both <strong>macOS</strong> and <strong>Linux</strong>, and then publish them directly to a <strong>GitHub Release</strong> in your repository.</p>
<h2><a href="https://www.avanderlee.com/optimization/app-design-5-benefits-of-using-system-components/">🖼️ App design: 5 benefits of using system components</a></h2>
<p>Creating <strong>custom elements</strong> and bypassing the often mundane system components in app design might initially seem appealing.</p>
<p>However, these system elements come with several advantages that are easy to overlook, potentially causing you to miss out on <strong>built-in</strong> functionalities.
In <a href="https://x.com/twannl">Antoine's</a> latest article, he outlines <strong>five</strong> key benefits of utilizing system components: <strong>built-in accessibility</strong>, <strong>user familiarity</strong>, <strong>accelerated design process</strong>, <strong>consistent design that leads to a better user experience</strong>, and <strong>optimized affordance</strong> — all provided at no extra cost.</p>
<p>When your app designer sends you a highly intricate UI that seems like it will take ages to implement, I highly recommend sharing this article with him — I am sure he will love it 🤣!</p>
<h2><a href="https://codingwithvera.com/how-senior-developers-fix-problems/">👴🏻 How Senior Developers Fix Problems</a></h2>
<p>As a developer, you have probably faced problems where you thought, &quot;<em>I wish I had a Senior developer to consult...</em>&quot; or wondered, &quot;<em>How would a Senior developer tackle this?</em>&quot; I know I have, many times.</p>
<p><a href="https://x.com/CodingWithVera">Vera</a>, an <strong>iOS</strong> developer from 🇵🇹, wrote an insightful article on this very topic, outlining a <strong>personal framework</strong> she uses to solve problems, whether they are software-related or not.
I wish I had come across this article six years ago when I first started <strong>iOS development</strong>.
Back then, I often felt discouraged when I got stuck and questioned whether I was cut out for <strong>software development</strong>.</p>
<p>Now, with more experience under my belt, I understand that struggling with challenges is part of the process. While my experience might help me overcome some obstacles, I also know it is perfectly okay to seek help after exhausting my options.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[🚀 Deploy server side Swift apps on Vercel and master Xcode File Headers and Macros 📔]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue9</link>
            <guid>9</guid>
            <pubDate>Fri, 02 Aug 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[I want to extend my gratitude to all subscribers for their recent submissions and constructive feedback. The newsletter has been growing and provides a platform for developers to share their work and ideas. However, assembling it all requires significant time and effort.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>9th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.
I want to extend my gratitude to all subscribers for their recent submissions and constructive feedback. The newsletter has been growing and provides a platform for developers to share their work and ideas. However, assembling it all requires significant <strong>time</strong> and <strong>effort</strong>.</p>
<p>I am setting aside space in the newsletter for <strong>developers</strong> and <strong>brands</strong> to <strong>showcase</strong> their <strong>products</strong> or <strong>ideas</strong>, with more details coming next week.</p>
<p>I am excited to kick off this new format by highlighting <a href="https://x.com/twannl">Antoine's</a> latest <a href="https://t.co/ybdnXP9Tnz">course</a>. It was a pleasure to chat with him, and I couldn't be happier to share his newest adventure!</p>
<p>Enough about my week, let's dive into some <strong>iOS</strong> development topics, shall we? Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://swift.cloud/blog/deploy-server-side-swift-applications-on-vercel">🚀 Deploy server side Swift applications on Vercel</a></h2>
<p><a href="https://vercel.com/">Vercel</a> offers a comprehensive solution for front-end developers to deploy their applications using modern best practices.
It integrates seamlessly with <strong>GitHub</strong> to deploy every commit and provides features like a fast CDN, preview deployments, API routes, local testing environments, and more.</p>
<p>I have chosen <strong>Vercel</strong> to host all my <strong>JavaScript-based</strong> websites because of these robust capabilities.
Thanks to <a href="https://x.com/andrew_barba">Andrew</a>, we can now also deploy serverless <strong>Swift</strong> applications, including websites and APIs, using <strong>Vercel</strong>.
In his article, <strong>Andrew</strong> demonstrates his work on a <strong>Swift runtime</strong> and a <strong>SPM plugin</strong> that simplifies deploying <strong>Swift</strong> applications on the <strong>Vercel</strong> platform. Great job by <strong>Andrew</strong> and other contributors!</p>
<h2><a href="https://www.youtube.com/watch?v=RACepNDGNyk">📔 Xcode File Headers and Macros</a></h2>
<p>Ever wanted to customize the default comments at the top of every file created in <strong>Xcode</strong>?</p>
<p>In this video tutorial, <a href="https://x.com/StewartLynch">Stewart</a> demonstrates how to create your own version of the <strong>Xcode File Header</strong>.
These comments are crafted from a mix of text and <a href="https://help.apple.com/xcode/mac/9.0/index.html?localePath=en.lproj#/dev7fe737ce0">text macros</a>, defined in a property list file called <code>IDETemplateMacros</code>.
This file must be placed in one of <a href="https://help.apple.com/xcode/mac/9.0/index.html?localePath=en.lproj#/dev91a7a31fc">five specific locations</a> to be recognized.
For those who need to share this file across multiple Macs, <strong>Stewart</strong> also offers a solution using <strong>iCloud Drive</strong> and <strong>symbolic links</strong>.</p>
<h2><a href="https://azamsharp.com/2024/07/29/navigation-patterns-in-swiftui.html">➡️ Navigation Patterns in SwiftUI</a></h2>
<p>Navigating in <strong>SwiftUI</strong> applications has always been a bit challenging.
Initially, <strong>SwiftUI</strong> introduced <code>NavigationView</code>, which was simple to use for basic list navigation.
However, implementing programmatic navigation was quite tricky.
I recall my early days with <strong>SwiftUI</strong> and how straightforward it was to set up basic list navigation, but programmatic navigation was another story.</p>
<p>With <strong>iOS 16</strong>, <code>NavigationView</code> was replaced by <code>NavigationStack</code>, which improved navigation by enabling dynamic and programmatic routing.
In his article, <a href="https://x.com/azamsharp">Mohammad Azam</a> delves into common navigation patterns that are useful when building <strong>SwiftUI</strong> applications, providing insights into how these new navigation tools can be effectively utilized.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Server Side Swift</category>
        </item>
        <item>
            <title><![CDATA[⏳ Async await in Swift and Building Swift Executables 👷]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue8</link>
            <guid>8</guid>
            <pubDate>Fri, 26 Jul 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Since our office is in Aveiro, we took advantage of the good weather and headed to a beachside bar. We enjoyed plenty of food, drinks, and fun activities like target archery, beach volleyball, and karaoke.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>8th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬. Last week, my company organized a fantastic team-building event with all team members, including me!</p>
<p>Since our office is in Aveiro, we took advantage of the good weather ☀️ and headed to a beachside bar 🏖️.
We enjoyed plenty of food, drinks, music and fun activities like target archery, beach volleyball, and karaoke.
I find these events crucial because they bring people together (we miss some human interaction with remote work right ?) and help build stronger bonds among team members.
What kinds of team-building events have you attended? Let me know!</p>
<p>Enough about me, let's dive into some iOS development topics, shall we? Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.emergetools.com/blog/posts/swift-async-await-the-full-toolkit">🧰 Async await in Swift: The Full Toolkit</a></h2>
<p><a href="https://x.com/jacobs_handle">Jacob</a> from <a href="https://x.com/emergetools">Emerge Tools</a> has written an article that delves into the tools available in <strong>Swift Concurrency</strong>, explaining when and how to use them.
This well-crafted piece quickly became one of my top reads on the subject, thanks to its clear, concise explanations and practical code examples.
<strong>Jacob</strong> begins by discussing the theoretical aspects where necessary and, for each tool, concludes with a context where it might be the ideal solution.
If you are looking for a thorough yet straightforward guide on <strong>Swift Concurrency</strong>, this article is a must-read 🔥!</p>
<blockquote>
<p>For those seeking a more introductory overview on the topic, check out <a href="https://www.tiagohenriques.dev/blog/modern-concurrency-in-swift">my guide on Swift Concurrency</a>!</p>
</blockquote>
<h2><a href="https://www.avanderlee.com/swiftui/memory-consumption-loading-uiimage-from-disk/">⛔ Memory consumption when loading UIImage from disk</a></h2>
<p>Loading images from disk into an in-memory array can significantly increase memory usage.
In <a href="https://x.com/twannl">Antoine's</a> latest article, he discusses techniques to optimize memory consumption: by rewriting code to use <strong>non-system caching APIs</strong> and implementing an <strong>NSCache-based</strong> solution for apps requiring image processing, you can drastically improve your app's memory efficiency.</p>
<h2><a href="https://digitalbunker.dev/debug-description-macro-xcode-16/">📓 Using @DebugDescription in Xcode 16</a></h2>
<p>Debugging custom types can be challenging, but having clear and informative debug output is crucial for understanding your code's behavior.
The <a href="https://developer.apple.com/documentation/swift/customdebugstringconvertible">CustomDebugStringConvertible</a> protocol and the new <a href="https://developer.apple.com/documentation/swift/debugdescription()?changes=latest_minor">@DebugDescription</a> macro in <strong>Xcode 16</strong> can greatly assist with this.
In <a href="https://x.com/aryamansharda">Aryaman's</a> article, you will learn how to effectively use this protocol and macro to simplify and enhance your debugging process.</p>
<h2><a href="https://www.rudrank.com/exploring-indie-life-reducing-friction-by-ci-cd/">🧞 Exploring Indie Life: Reducing Friction by CI/CD</a></h2>
<p>Manually shipping apps is a tedious and repetitive task that <a href="https://x.com/rudrankriyam">Rudrank</a> believes should be automated as soon as possible.
He fully embraces the <em>&quot;automate first, code later&quot;</em> principle, which he says has greatly reduced the friction of shipping apps.
In this article, <strong>Rudrank</strong> leverages the free minutes of his <a href="https://developer.apple.com/xcode-cloud/">Xcode Cloud</a> <strong>Apple Developer</strong> membership to push builds simultaneously to three platforms: <strong>iOS, macOS, and visionOS</strong>.</p>
<h2><a href="https://swifttoolkit.dev/posts/building-swift-executables">👷 Building Swift Executables</a></h2>
<p>You have developed your <strong>Swift CLI</strong> executable, and now you are wondering how to make it available to other people?
In this article, <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> covers key considerations and provides detailed build instructions, including how to create <strong>universal binaries</strong> and support <strong>Linux</strong>.</p>
<blockquote>
<p>Although the article doesn't mention Windows support, I outlined a solution from a <a href="https://github.com/henriquestiagoo/cli-chatgpt/blob/main/.github/workflows/windows.yml">previous project</a>. Using GitHub Actions, I built a CLI executable in a Windows environment, uploaded the artifact to the Action run, and downloaded it from there.</p>
</blockquote>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[🧑‍💻 My first iOS Conference, Daily insights on TCA and Learn all about building macOS utilities 💻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue7</link>
            <guid>7</guid>
            <pubDate>Sat, 20 Jul 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I received an email that made my day! I have been confirmed to attend Swift Leeds. I couldn't be more thrilled, as this will be my very first iOS conference. I was waiting to hear back from my company about covering some of the conference and travel expenses, and thankfully, everything worked out.]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>7th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong> 📬.
This week I received an email that made my day! I have been confirmed to attend <a href="https://swiftleeds.co.uk/">Swift Leeds</a>.</p>
<p>I couldn't be more thrilled, as this will be my very first <strong>iOS</strong> conference.
I was waiting to hear back from my company about covering some of the conference and travel expenses, and thankfully, everything worked out.
I am really looking forward to meeting the developers I follow on <strong>Twitter</strong> and sharing ideas.
Will you be there too? I would love to buy you a <strong>coffee</strong> ☕!</p>
<p>Enough about me, let's dive into some <strong>iOS</strong> development topics, shall we?
Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://www.linkedin.com/in/romain-brunie-the-composable-architecture/">🗓️ Daily insights on TCA</a></h2>
<p>If you are using or interested in <a href="https://github.com/pointfreeco/swift-composable-architecture">The Composable Architecture</a> <strong>(TCA)</strong>, you should definitely follow <a href="https://www.linkedin.com/in/romain-brunie-the-composable-architecture/">Romain</a> on <strong>LinkedIn</strong>.
<strong>Romain</strong> shares daily insights and personal experiences to help you master <strong>TCA</strong> 🚀.
For those looking to enhance their <strong>TCA</strong> skills, check out his free <a href="https://learnwithromain.github.io/swift-composable-architecture/main/tutorials/refinecomposablearchitecture/">interactive tutorial</a> on <strong>TCA</strong> best practices.</p>
<h2><a href="https://jacobbartlett.substack.com/p/how-to-consistently-get-48-app-ratings-3be">⭐ How to (consistently) get 4.8* App Ratings</a></h2>
<p><a href="https://x.com/jacobs_handle">Jacob</a> wrote an article some time ago on how to improve your review score with two straightforward strategies: <strong>requesting reviews</strong> and pinpointing your <strong>&quot;wow&quot;</strong> moment.
I found his insights incredibly valuable, especially since I have struggled to get positive reviews for my side project, <a href="https://www.padeltime.app/">Padel Time</a>.
Now it is time to apply these tips and see the results!</p>
<h2><a href="https://digitalbunker.dev/blend-modes-in-swiftui/">🦎 Blend Modes in SwiftUI</a></h2>
<p>Experimenting with <a href="https://developer.apple.com/documentation/swiftui/blendmode">blend modes</a> in <strong>SwiftUI</strong> can greatly enhance your design's visual impact.
In this article, <a href="https://x.com/aryamansharda">Aryaman</a> demonstrates how applying various <strong>.blendMode()</strong> modifiers to a standard view can yield intriguing and creative results.</p>
<h2><a href="https://brightinventions.pl/blog/ios-build-run-tests-github-actions/">🤖 Build and Run iOS App Tests with GitHub Actions</a></h2>
<p>Last week, <a href="https://x.com/Sulinskii">Artur</a> from <a href="https://brightinventions.pl/">Bright Inventions</a> set up a <a href="https://fastlane.tools/">Fastlane</a> lane to run tests locally.
This time, he extends that work by creating a <a href="https://github.com/features/actions">GitHub Actions</a> pipeline, which triggers on changes to the <strong>main</strong> branch using the same <strong>Fastlane</strong> lane.</p>
<h2><a href="https://www.avanderlee.com/swiftui/macos-development-powerful-utilities/">💻 Why macOS Development is Perfect for Indie Developers</a></h2>
<p>For those of you aiming to become <strong>indie</strong> developers, <a href="https://x.com/twannl">Antoine</a> has an excellent article that makes <strong>macOS</strong> development more approachable.
In this piece, <strong>Antoine</strong> invites <a href="https://x.com/jordibruin">Jordi Bruin</a> to share his journey into <strong>macOS</strong> indie development.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[💻 Using SwiftUI in CLI Tools, SwiftUI Advanced Learning and Learn how to setup CI/CD pipelines with Fastlane 🚀]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue6</link>
            <guid>6</guid>
            <pubDate>Fri, 12 Jul 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Welcome to the 6th issue of the iOS Coffee Break Newsletter. Feel free to reach out to me on Twitter and share your suggestions for what you would like to see featured in the newsletter!]]></description>
            <content:encoded><![CDATA[<p>Welcome to the <strong>6th</strong> issue of the <strong>iOS Coffee Break Newsletter</strong>.
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a> and share your suggestions for what you would like to see featured in the <strong>newsletter</strong>!
Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<blockquote>
<p>On a different note, Euro 2024 is nearing its climax! After some underwhelming matches, Spain 🇪🇸 and England 🏴󠁧󠁢󠁥󠁮󠁧󠁿 will face off tomorrow in the highly anticipated final 🏆! Who are you cheering for?</p>
</blockquote>
<h2><a href="https://swifttoolkit.dev/posts/swiftui-meets-command-line">💻 Using SwiftUI in Command Line Tools</a></h2>
<p>SwiftUI's <a href="https://developer.apple.com/documentation/swiftui/imagerenderer">ImageRenderer</a> class offers a straightforward and intuitive <strong>API</strong> for exporting any view as an image.
In his latest article, <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> demonstrates how to utilize this feature within a <strong>Command Line Tool</strong> to add badges to an app icon.</p>
<h2><a href="https://www.youtube.com/playlist?list=PLwvDm4Vfkdphc1LLLjCaEd87BEg07M97y">📖 SwiftUI Advanced Learning</a></h2>
<p>This week, I stumbled upon <a href="https://x.com/swiftfulthinkng">Nick's</a> YouTube channel, <a href="https://www.youtube.com/@SwiftfulThinking">Swiftful Thinking</a>, and started checking out some of his playlists.
I have already watched the first eight videos from the <a href="https://www.youtube.com/playlist?list=PLwvDm4Vfkdphc1LLLjCaEd87BEg07M97y">Swift Advanced Learning</a> series, where he dives into advanced topics like building custom views, animations, transitions, and using generics.
I will definitely finish the series when I have more time because <strong>Nick</strong> covers valuable <strong>SwiftUI</strong> topics.</p>
<h2><a href="https://brightinventions.pl/blog/building-running-ios-app-test-locally-fastlane/">🚀 Building and Running iOS App Tests Locally with Fastlane</a></h2>
<p>If you are hoping to kickstart your app development journey and run tests locally with <a href="https://fastlane.tools/">Fastlane</a>, check out <a href="https://x.com/Sulinskii">Artur's</a> step-by-step iOS <strong>CI/CD</strong> tutorial.
The first part is already available, with two more articles on the way!</p>
<h2><a href="https://x.com/pointfreeco/status/1811070557170942428">🔎 Swift Testing support for SnapshotTesting</a></h2>
<p><a href="https://x.com/pointfreeco">Point Free</a> has just released an update (<a href="https://github.com/pointfreeco/swift-snapshot-testing/releases/tag/1.17.0">version 1.17.0</a>) for their popular <a href="https://github.com/pointfreeco/swift-snapshot-testing">SnapshotTesting</a> library, now supporting the new <strong>Swift Testing</strong> framework alongside their <a href="https://github.com/pointfreeco/swift-macro-testing">MacroTesting</a> library.
If you are using these libraries and are unsure about how to migrate to the new releases, be sure to check out their informative <a href="https://www.pointfree.co/blog/posts/146-swift-testing-support-for-snapshottesting">article</a>, which includes useful examples to help you get started.</p>
<h2><a href="https://www.polpiella.dev/newer-version-lookup/">🆕 Check if your app has a newer version on the App Store using Swift</a></h2>
<p><a href="https://x.com/polpielladev">Pol</a> and <a href="https://x.com/hiddevdploeg">Hidde</a> recently built a feature for <strong>Helm</strong> to let users know when a new version of your app is available.
<strong>Pol</strong> decided to dive deep and explore all the ways you can do this in his latest <a href="https://www.polpiella.dev/newer-version-lookup/">article</a>.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[🔨 The Swift Argument Parser, Useful Aliases and Toxic Perfectionism 🎮]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue5</link>
            <guid>5</guid>
            <pubDate>Fri, 05 Jul 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Last week, I took a short vacation to Algarve to take a rest from work! If you haven't visited the southern part of Portugal, I highly recommend taking a break to explore its sandy beaches.]]></description>
            <content:encoded><![CDATA[<p>Last week, I took a short vacation to <strong>Algarve</strong> to take a break from work!
If you haven't visited the southern part of Portugal 🇵🇹, I highly recommend taking a break to explore its sandy beaches 🏖️, enjoy the warm weather ☀️ and savor the amazing Portuguese cuisine 🍲.
Feel free to reach out to me on <a href="https://x.com/tiagodhenriques">Twitter</a> if you need any tips for the best spots.</p>
<p>Here are this week's highlighted resources. Hope you enjoy 🙌.</p>
<h2><a href="https://fatbobman.com/en/posts/mastering-the-swift-testing-framework/">👨‍🔬 Swifter and Swifty: Mastering the Swift Testing Framework</a></h2>
<p>This week, I discovered <a href="https://fatbobman.com">Xu Yang's</a> blog, and I am amazed 😮 I hadn't found it sooner given the high quality of the content.
In this article <strong>Xu</strong>, that writes articles under the name <a href="https://x.com/fatbobman">Fatbobman</a>, explores the features, usage, and unique aspects of the <strong>Swift Testing</strong> framework, highlighting how it helps developers write test code more quickly and in line with Swift programming practices.</p>
<h2><a href="https://swifttoolkit.dev/posts/categories/argument-parser">🔨 The Interactive Swift Argument Parser Guide</a></h2>
<p>Planning to build your next <strong>command line</strong> tool? A few months ago, <a href="https://x.com/SwiftToolkit">Swift Toolkit.dev</a> published a three-part guide on leveraging the <strong>Swift Argument Parser</strong> to create new tools.
The first part covers the basics: creating a new tool, commands, subcommands, and arguments.
The second part dives into flags, name specifications, flag inversions and enumerable flags.
The third and final part explores options and exiting.
In my opinion, this guide is one of the most comprehensive resources on the <strong>Swift Argument Parser</strong>, so I highly recommend you checking it out ✅!</p>
<h2><a href="https://digitalbunker.dev/useful-terminal-aliases-for-ios-development/">⏩ Useful Aliases for Everyday iOS Development</a></h2>
<p>In this article, <a href="https://x.com/aryamansharda">Aryaman</a> shares several useful aliases for <strong>Xcode</strong>, <strong>CocoaPods</strong>, <strong>Git</strong>, and more to streamline your workflow.
These tips aim to reduce context switching, allowing you to focus more on coding and less on managing tools.</p>
<h2><a href="https://codingwithvera.com/how-stardew-valley-helped-me-overcome-perfectionism/">🎮 How I Overcame My Perfectionism Through Stardew Valley</a></h2>
<p><a href="https://x.com/CodingWithVera">Vera</a> decided to share a personal milestone: learning to cope with her perfectionist mindset.
She writes about the open-ended country-life RPG, <strong>Stardew Valley</strong>, and how playing it offered her new perspectives.
I can completely relate to her experience, as I have also felt like I could and should have done better at a task, only to end up procrastinating and doing nothing!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[🧪 Swift Testing, Explicitly build modules and Upcoming iOS conferences 🗓️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue4</link>
            <guid>4</guid>
            <pubDate>Thu, 27 Jun 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[This week I have been pretty busy at work, but was able to put some time to get along with what is new within the community. I am also thrilled to announce that I received my first submissions to the platform, and I am super happy to feature them in this week's issue!]]></description>
            <content:encoded><![CDATA[<p>This week I have been pretty busy at work, but was able to put some time to get along with what is new within the community.</p>
<p>Yesterday, I had the chance to attend to <a href="https://x.com/polpielladev">Pol's</a> <strong>Xcode Cloud</strong> workshop, and it was 🔥.
He revealed some behind-the-scenes magic 🪄 and gave a comprehensive overview of how <strong>Xcode Cloud</strong> operates.
We explored practical use cases on his app <strong>QReate</strong>, including setting up dependencies, creating <strong>CI/CD</strong> workflows to run tests, uploading the app to external services, generating release notes, and much more!
The three hours flew by, and I can't wait to apply all the knowledge I gained!</p>
<p>I am also thrilled to announce that I received my first <strong>submissions</strong> to the platform, and I am super happy to feature them in this week's issue!
Hope you enjoy 🙌.</p>
<h2><a href="https://codingwithvera.com/discover-swift-testing/">👋 Say Goodbye to XCTest</a></h2>
<p><strong>Swift Testing</strong> has emerged as one of the standout features from <strong>WWDC24</strong>.
<strong>Apple's</strong> new framework will be the default when creating a new project starting from <strong>Xcode</strong> 16.
<a href="https://x.com/CodingWithVera">Vera’s</a> latest article offers a comprehensive overview of this new framework, showcasing code examples that illustrate how features like <strong>tagging</strong> and <strong>parameterized</strong> testing work.</p>
<h2><a href="https://x.com/Dimillian/status/1805533661023879179">🆕 New ScrollView SwiftUI API</a></h2>
<p>This week, <a href="https://x.com/Dimillian">Thomas</a> tweeted about the new <strong>ScrollView</strong> <strong>SwiftUI</strong> API in <strong>iOS 18</strong>, sharing a code snippet that demonstrates how to easily hide the navigation bar and the tab bar when scrolling.
This is achieved using the <strong>onScrollPhaseChange</strong> view modifier in combination with the <strong>toolbarVisibility</strong> method.
At work, I had previously achieved this effect using <strong>UIKit’s</strong> intricate methods, but now with <strong>SwiftUI</strong>, it can be done with just a few lines of code 😮.</p>
<h2><a href="https://peterfriese.dev/blog/2024/hero-animation/?utm_campaign=Not%2BOnly%2BSwift&amp;utm_medium=email&amp;utm_source=Not_Only_Swift_64">🔍 SwiftUI Hero Animations with NavigationTransition</a></h2>
<p>With the introduction of the <strong>NavigationTransition</strong> protocol in <strong>iOS 18</strong>, implementing a hero animation in <strong>SwiftUI</strong> takes just three lines of code.
I mentioned this new feature in last week's article, but this article takes this new API to a whole new level.
<a href="https://x.com/peterfriese">Peter's</a> article will guide you through creating a hero animation similar to the one in the <strong>App Store’s</strong> Today view and show you how to turn it into a reusable <strong>SwiftUI</strong> component.</p>
<h2><a href="https://bitrise.io/blog/post/demystifying-explicitly-built-modules-for-xcode">🧙‍♀️ Demystifying Explicitly build modules for Xcode</a></h2>
<p>One of the new features in <strong>Xcode 16</strong> is called <strong>explicitly built modules</strong>.
Despite its abstract name, this feature enhances build speed and makes compiler errors more informative.
This <a href="https://bitrise.io/">bitrise</a> article delves into how this feature works and the advantages it offers to projects that adopt it.
While the benchmarks discussed do not show performance improvements yet, we may see more accurate results with the final release of <strong>Xcode 16</strong>.</p>
<h2><a href="https://x.com/TouchlabHQ/status/1805329791442141341">🌟 Multiplatform Compose + SwiftUI = The Native App Future</a></h2>
<p>Blending <strong>Compose UI</strong> and <strong>SwiftUI</strong> on <strong>iOS</strong> offers app developers the opportunity to create mostly-native experiences from mostly-shared <strong>Kotlin</strong>.
<a href="https://x.com/TouchlabHQ">Touchlab</a> gives a 1-hour live stream event showcasing advanced <strong>Compose MP + SwiftUI</strong> techniques.
I got to admit that I am skeptical about cross platform tools but I am willing to give it a try!
If you are interested to <strong>join</strong>, do it now because the workshop is <strong>tomorrow</strong>!</p>
<h2><a href="https://dev.events/ios">🗓️ Upcoming iOS Conferences 2024</a></h2>
<p>As <strong>iOS</strong> developers,<strong>WWDC24</strong> is the conference we eagerly anticipate each year. Now that it has concluded, let's look forward to the upcoming developer conferences.
<a href="https://x.com/IOSDEVUK">iOSDevUK</a>, <a href="https://x.com/NSSpain">NSSpain</a>, <a href="https://x.com/swift_leeds">Swift Leeds</a>, <a href="https://x.com/iOSConf">DO iOS</a>, and more are on the horizon!
I am really excited and hopeful to attend my first conference this year and have a chat with some of you, fingers crossed 🤞!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[Exploring WWDC24 new features 🕵️‍♂️]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue3</link>
            <guid>3</guid>
            <pubDate>Thu, 20 Jun 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[A week has passed since Apple WWDC24, and the iOS community is already diving into the new features. Personally, I split my time between reviewing some WWDC24 sessions and following Euro 2024, particularly cheering for my team, Portugal.]]></description>
            <content:encoded><![CDATA[<p>A week has passed since <strong>Apple WWDC24</strong>, and the <strong>iOS community</strong> is already diving into the new features.
Personally, I split my time between reviewing some <strong>WWDC24</strong> sessions and following <strong>Euro 2024</strong>, particularly cheering for my team, Portugal 🇵🇹.
Now, let's take a look at some of the exciting new features that <strong>Apple</strong> has introduced from a dev's perspective. Hope you enjoy 🙌.</p>
<h2><a href="https://www.polpiella.dev/swift-testing">👷 Getting Started with Swift Testing</a></h2>
<p>If you got excited about <a href="https://developer.apple.com/documentation/testing">Swift Testing</a>, <strong>Apple's</strong> new macro-based testing library, like I did, you should definitely take a look at <a href="https://x.com/polpielladev">Pol Piela’s</a> latest article.
Last week, Pol wrote an article about how you can get started using it and how you can migrate your existing <strong>XCTest</strong> tests to the new library.
I personally enjoy this new method of writing tests, and I believe it will finally make the process enjoyable for me.</p>
<h2><a href="https://swiftwithmajid.com/2024/06/10/what-is-new-in-swiftui-after-wwdc24/">👀 What is new in SwiftUI after WWDC24</a></h2>
<p><a href="https://x.com/mecid">Majid</a> provided an excellent article exploring the latest features introduced in the <strong>SwiftUI</strong> framework.
He covered topics as the new overloads for Group and ForEach views, the enhanced tab bar experience, hero animations, scroll position handling, the entry macro that allow us to quickly introduce environment values, focused values, etc, without boilerplate, previews and its new <strong>@Previewable</strong> macro, and more.</p>
<h2><a href="https://www.youtube.com/watch?v=zWW--SAoyVc">🎨 Mesh Gradient Creator</a></h2>
<p>I have been following <a href="https://www.youtube.com/@StewartLynch">Stewart Lynch's YouTube series</a> for a while, and once again, <a href="https://x.com/StewartLynch">Stewart</a> has provided an excellent resource to the community.
To better understand the new <a href="https://developer.apple.com/documentation/swiftui/meshgradient">Mesh Gradient</a> view introduced at <strong>WWDC24</strong>, Stewart developed a Mac app that lets you experiment with the grid of points, their coordinates, and colors.
I highly recommend downloading the app, as it offers an option to either save the code for use in your own projects or to download a desktop image based on your creation.</p>
<h2><a href="https://augmentedcode.io/2024/06/17/zoom-navigation-transition-in-swiftui/">🔍 Zoom navigation transition in SwiftUI</a></h2>
<p><strong>WWDC24</strong> introduced a variety of updates, with <strong>SwiftUI</strong> receiving significant enhancements.
One notable addition is the new <a href="https://developer.apple.com/documentation/swiftui/navigationtransition">NavigationTransition</a> protocol, which includes the zoom transition.
<a href="https://x.com/toomasvahter">Thoomas Vahter</a> illustrates this feature with a grid view example that opens a DetailView using the zoom transition.
To achieve this effect, you can simply apply the <strong>navigationTransition</strong> view modifier to the destination view and the <strong>matchedTransitionSource</strong> view modifier to the originating view.</p>
<h2><a href="https://nilcoalescing.com/blog/EnhancedReplaceTransitionForSFSymbolsInIOS18/">💨 Enhance replace transition for SF symbols in iOS 18</a></h2>
<p><strong>iOS 18</strong> introduces a new feature for the <a href="https://developer.apple.com/documentation/symbols/replacesymboleffect">ReplaceSymbolEffect</a> called <strong>MagicReplace</strong>.
This option enables smooth animations for slashes and badges in SF Symbols, improving visual transitions in your apps.
<a href="https://x.com/natpanferova">Natalia Panferova</a> showcases this feature with an example of a notification toggle, resulting in a seamless magic replace animation on the bell icon when the slash is added or removed.</p>
<h2><a href="https://helm-app.com/">💻 Helm for App Store Connect</a></h2>
<p>This is the only topic outside <strong>WWDC</strong> in today's issue, but I really want to highlight it!
<a href="https://x.com/polpielladev">Pol Piela</a> and <a href="https://x.com/hiddevdploeg">Hidde van der Ploeg</a> released <a href="https://helm-app.com/">Helm</a> last week, a native <strong>macOS</strong> app designed to make using <strong>App Store Connect</strong> easier and more enjoyable for shipping apps and updates.
I am super excited to try it out and can't wait to upload a new build without needing to open <strong>App Store Connect</strong> to double-check anything!</p>
<h2>Conclusion</h2>
<p><strong>Apple WWDC 2024</strong> has set the stage for another exciting year within the <strong>Apple</strong> ecosystem, and the <strong>iOS community</strong> has quickly begun diving into these new features.
I hope you enjoy the post. Feel free to follow me on <a href="https://x.com/tiagodhenriques">Twitter</a> and ask any questions you have related to this content.
Thanks for reading, and see you next week!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[ WWDC 2024 highlights for developers 🧑‍💻]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue2</link>
            <guid>2</guid>
            <pubDate>Fri, 14 Jun 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[The highly awaited WWDC 2024 has just wrapped up, and Apple has once again introduced a series of groundbreaking announcements set to transform the tech industry. Here is a brief overview of the major highlights from this year's event.]]></description>
            <content:encoded><![CDATA[<p>&lt;StaticImage
src=&quot;/issues/issue2/swiftui.jpeg&quot;
alt=&quot;WWDC SwiftUI poster.&quot;
link=&quot;/issues/issue2/swiftui.jpeg&quot;
caption=&quot;WWDC SwiftUI poster.&quot;
/&gt;</p>
<p>The highly awaited <strong>WWDC 2024</strong> has just wrapped up, and <strong>Apple</strong> has once again introduced a series of groundbreaking announcements set to transform the tech industry. Here is a brief overview of the major highlights from this year's event. Hope you enjoy 🙌.</p>
<blockquote>
<p>This issue is somewhat beyond the focus of this newsletter, but following an incredible week at WWDC, I would like to express my gratitude 🙏 to the initial subscribers by providing a summary of the key highlights that I believe are most important for Apple developers.</p>
</blockquote>
<h2><a href="https://www.apple.com/apple-intelligence/">Introduction of Apple Intelligence</a></h2>
<p>The next big step for <strong>Apple</strong> is here. <strong>Apple Intelligence</strong> is a personal intelligence built into your devices to help you write, express yourself, and get things done effortlessly.
It is deeply integrated into features and apps across the system, and built with privacy from the ground up.</p>
<p><strong>Apple Intelligence</strong> starts with Apple's <strong>on-device</strong> foundation model and it is extended to the cloud with <strong>Private Cloud Compute</strong> to run larger foundation models.</p>
<h2><a href="https://developer.apple.com/apple-intelligence/">Writing Tools, Genmoji 🥳 and Image Playground</a></h2>
<p><a href="https://developer.apple.com/videos/play/wwdc2024/10168/">Writing Tools</a>, <a href="https://developer.apple.com/videos/play/wwdc2024/10220/">Genmoji</a> and <strong>Image Playground</strong> are three powerful new <strong>Apple Intelligence</strong> features that will for sure delight users by integrating these into your apps.</p>
<p><strong>Writing Tools</strong> aim to help users rewrite, proofread and summarize text.
The cool thing is that if you are using any of the standard UI frameworks to render TextFields, TextViews, your app will automatically get <strong>Writing Tools</strong>!
If you want to customize how your app behave while <strong>Writing Tools</strong> is active, you just need to use <strong>Apple's</strong> new TextView delegate API.</p>
<p><strong>Genmoji</strong> opens up entirely new ways to communicate, letting users create a new emoji to match any moment.</p>
<p>The new <strong>Image Playground API</strong> delivers a consistent and easy-to-use experience.
With this API, users can edit the prompt supplied to them to create an image that represents anything they want that is unique and can be stored on device.
I am really excited about this because I can already see lots of useful use cases to work on! 💪</p>
<h2><a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes">Xcode 16, Code Completion and Swift Assist</a></h2>
<p><a href="https://developer.apple.com/videos/play/wwdc2024-10135">Xcode 16</a> has many new features to make you more productive and improve the quality of your apps.
Things like a single view of your backtraces, showing relevant code from all stack frames together, deeper insight into your app's performance and enhancements to localization catalogs.
<strong>Xcode 16</strong> also marks a whole new chapter for development, as Apple infuse its tools with the power of Generative Models.</p>
<p><strong>Code Completion</strong> is an innovative new engine that can predict the code you need. It uses your project symbols to customize suggestions.
It runs locally on your Mac, keeping your code private, giving you super-fast results, and even works when you are offline.
<strong>Xcode</strong> can even use the comments you write as context, given you a suggestion as soon as you start typing.</p>
<p><strong>Swift Assist</strong> is a companion for all of your coding tasks and I have to say, one of my favorite announcements this year!
<strong>Swift Assist</strong> can answer your coding questions and help with tasks like experimenting with new APIs.
Like <strong>code completion</strong>, <strong>Swift Assist</strong> uses details from your project, including symbols and the relationships between them, to create personalized code.</p>
<p>My concern here is somehow my information is exposed to train machine learning models for example, and I don't want that for sure!
However, Apple states that all of these tools are built with your privacy and security in mind.
<strong>Swift Assist</strong> will be available later this year and I can't wait to try it out ✨.</p>
<h2><a href="https://developer.apple.com/videos/play/wwdc2024/10136/">Swift, Swift 6 and Swift Testing</a></h2>
<p><strong>Apple</strong> is working with the open source community to bring <strong>Swift</strong> to more platforms and domains.
<strong>Swift</strong> is given support for Visual Studio Code and other editors. Linux support was expanded to include more distributions and the Windows support for Windows was also improved.</p>
<p><a href="https://www.swift.org/migration/documentation/migrationguide/">Swift 6</a> makes concurrent programming dramatically easier by introducing data-race safety.
Other developments include improvements to concurrency, generics, and a new &quot;Embedded Swift&quot; subset for targeting highly-constrained environments like operating system kernels and microcontrollers.</p>
<p>Another important aspect of software development is writing tests.
<a href="https://developer.apple.com/videos/play/wwdc2024/10179/">Swift Testing</a> has expressive APIs that make it simple to write tests.
<strong>Swift Testing</strong> also includes a flexible tagging system to help you organize your tests and test plans.
With tags, you can selectively run tests across your test suite, like tests that use a certain module or that run on a specific device.
You can easily parameterize tests so that they can be reused multiple times. <strong>Xcode 16</strong> has full support for <strong>Swift Testing</strong>.</p>
<h2><a href="https://developer.apple.com/videos/play/wwdc2024/10144/">SwiftUI Previews and Interoperability between UI frameworks</a></h2>
<p>This year, <strong>Apple</strong> has focused on previews, customizations and interoperability.
<strong>Xcode Previews</strong> has a new dynamic linking architecture that uses the same build artifacts for previews for when you build-and-run.
This avoids rebuilding your project when switching between the two, making for a dramatically smoother and more productive workflow.</p>
<p>A new <strong>@Previewable</strong> macro makes it possible to use dynamic properties like <strong>@State</strong> directly in a <strong>Xcode Preview</strong>, making much more easier to set up <strong>SwiftUI</strong> previews.</p>
<p>Many apps adopting <strong>SwiftUI</strong> also use views written with <strong>UIKit</strong> and <strong>AppKit</strong>, so great interoperability with these frameworks is critical.
Now, UI frameworks share more common foundations. Gesture recognition has been factored out of <strong>UIKit</strong>, enabling you to take any built-in or custom <strong>UIGestureRecognizer</strong> and use it in your <strong>SwiftUI</strong> view hierarchy.</p>
<p>Also, <a href="https://developer.apple.com/videos/play/wwdc2024/10145/">animations</a> have been factored out of <strong>SwiftUI</strong> so you can now set up animations on <strong>UIKit</strong> or <strong>AppKit</strong> views and them drive them with <strong>SwiftUI</strong>, including fully custom animations.</p>
<h2><a href="https://www.apple.com/ios/ios-18-preview/">iOS and iPadOS 18</a></h2>
<p><strong>iOS</strong> is more customizable than ever, and it starts with <strong>Controls</strong>.
They make getting to frequent tasks from your apps faster and easier and are a great way to engage with your app from more places across the system.</p>
<p><strong>iPadOS</strong> delivers big updates to the ways that your users interact with your apps, starting with the <a href="https://developer.apple.com/videos/play/wwdc2024/10147/">redesigned tab bar</a>.
It floats at the top of your app and makes it easy to jump to your favorite tabs.
Additionally, it turns into a sidebar for those moments when you want to dive deeper. The most interesting feature for iPadOS for far!</p>
<h2><a href="https://www.apple.com/macos/macos-sequoia-preview/">WatchOS 11 and macOS Sequoia</a></h2>
<p>One of the coolest new features on <a href="https://developer.apple.com/videos/play/wwdc2024-10205">watchOS</a> this year actually starts on iOS: <a href="https://developer.apple.com/videos/play/wwdc2024-10068">Live Activities</a>.
Watch wearers will see your compact leading and trailing views automatically in the Smart Stack, as well when significant event notifications occur.
You can now bring your interactive widgets to <strong>watchOS</strong>, using the same APIs your are currently using on <strong>iOS</strong> and <strong>macOS</strong>.</p>
<p><strong>App Intents</strong> let you create widgets with multiple interactive areas that perform actions and update state directly in the widget.</p>
<p>And for those of you eager to integrate <strong>double tap</strong> into your apps, <strong>handGestureShortcut</strong> is the modifier you have been looking for.
Use this modifier to identify a <strong>Button</strong> or <strong>Toggle</strong> as the primary action in your app, widget or Live Activity to give your customers quick, one-handed control.</p>
<p>This year, <strong>macOS</strong> supports <strong>Apple Intelligence</strong> with features like <strong>Writing Tools</strong>, <strong>Genmoji</strong> and <strong>Image Playground</strong> that you can integrate right into your apps to create engaging experiences.
It also introduces productivity features like easier <strong>window tiling</strong>, <strong>iPhone mirroring</strong>, and delivers news APIs including user space file system support and major improvements to <strong>MapKit</strong>.</p>
<h2>Conclusion</h2>
<p><strong>Apple WWDC 2024</strong> has laid the foundation for another thrilling year within the <strong>Apple</strong> ecosystem.
With revolutionary updates spanning <strong>iOS</strong>, <strong>macOS</strong>, and new explorations into <strong>AR</strong> and <strong>health</strong>, <strong>Apple</strong> is once again pushing boundaries, equipping developers with state-of-the-art tools and delivering unmatched experiences to users.
Stay tuned for more in-depth coverage and tutorials on how to leverage these new technologies in your projects!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-engine/main/issues/2.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[🆕 Modern Concurrency in Swift, Vapor and Padel Time 🎾]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue1</link>
            <guid>1</guid>
            <pubDate>Mon, 20 May 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[Hi there, welcome to the 1st issue of iOS Coffee Break Newsletter. Today we will dive into how modern concurrency in Swift works how we can easily get started building Server-Side applications in Swift and take a look at **Padel Time**, an iOS/watchOS application, designed to help Padel players to keep track of their scores.]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>Example Issue Template</p>
</blockquote>
<p>Hi there, welcome to the 1st issue of <strong>iOS Coffee Break Newsletter</strong>.
Today we will dive into how <strong>modern concurrency</strong> in <strong>Swift</strong> works, how we can easily get started building <strong>Server-Side</strong> applications in <strong>Swift</strong> and take a look at <strong>Padel Time</strong>, an <strong>iOS/watchOS</strong> application, designed to help Padel players to keep track of their scores.
Hope you enjoy 🙌</p>
<h2><a href="https://www.tiagohenriques.dev/blog/bridge-completion-handlers-into-async-apis">How to bridge completion handlers into async APIs 🫱🏾‍🫲🏻</a></h2>
<p>In this article, <a href="https://www.tiagohenriques.dev/">Tiago</a> does show you how to use continuations to bridge his old <strong>completion handler</strong> code into the new <strong>async APIs</strong>.</p>
<p>The author presents an example of an <strong>HTTP GET</strong> request that fetches a list of posts. He then begans by defining a callback-based function and then, writes a second version of that same function using an <strong>async-await</strong> approach based on <strong>continuations</strong>.</p>
<h2><a href="https://www.tiagohenriques.dev/blog/how-to-deploy-vapor-app">How to deploy a Vapor application ☁️</a></h2>
<p>Last month, <a href="https://www.tiagohenriques.dev/">Tiago</a> did a series of articles on the work he did to explore how <strong>Vapor</strong> works.
<a href="https://vapor.codes/">Vapor</a> is a <strong>Server-Side Swift</strong> framework that leverages the power of <strong>Swift</strong> to make routing type-safe.</p>
<p>The author shows a deployment that runs locally using <strong>Docker</strong> an how you can deploy your <strong>Vapor</strong> application on a server so it becomes publicly available.</p>
<h2><a href="https://www.tiagohenriques.dev/blog/modern-concurrency-in-swift">Meet Modern Concurrency in Swift ⏳</a></h2>
<p>Last year at work, <a href="https://www.tiagohenriques.dev/">Tiago</a> felt the need to replace some parts of his codebase to adopt the new <strong>Modern Concurrency APIs</strong> in <strong>Swift</strong>.</p>
<p>So, in this short article, the author had prepared a <strong>getting started with modern concurrency guide</strong>, where he showcased how to fetch a list of articles <strong>asynchronously</strong> and how to can make use of <strong>grouped tasks</strong> to optimize performance.</p>
<h2><a href="https://www.tiagohenriques.dev/blog/increment-build-number-using-fastlane">Increment build number using Fastlane ⬆️</a></h2>
<p>I like reading articles like this one where code authors and maintainers use <strong>CI/CD</strong> workflows to automate tedious tasks to save time and effort and reduce the chances of making mistakes.</p>
<p>In this case, <a href="https://x.com/tiagodhenriques">Tiago Henriques</a> goes through how you can improve your <strong>CI/CD</strong> pipeline to increment the <strong>build number</strong> using <strong>Fastlane</strong>.</p>
<h2><a href="https://www.padeltime.app/">Padel Time, Your Score Tracker Companion 🎾</a></h2>
<p>&lt;StaticImage
src=&quot;/issues/issue1/padeltime3.png&quot;
alt=&quot;Padel Time - Your Score Tracker Companion.&quot;
link=&quot;/issues/issue1/padeltime3.png&quot;
caption=&quot;Padel Time - Your Score Tracker Companion.&quot;
/&gt;</p>
<p>Today, we are looking at <a href="https://apps.apple.com/us/app/padel-time/id6471981060">Padel Time</a> by <a href="https://x.com/tiagodhenriques">Tiago Henriques</a>.</p>
<p>With seamless point counting on your Apple Watch, <strong>Padel Time</strong> ensures precision and eliminates disputes, leaving you to focus on the game.
As simple as raising your arm and clicking on the winning team on each point.</p>
<p>Here are some important features:</p>
<ul>
<li>🎾 Count your points</li>
<li>📈 Track your progress anytime</li>
<li>🏋️‍♀️ Get match and workout statistics</li>
<li>🔒 Go premium to unlock score realtime updates</li>
<li>🧑‍🤝‍🧑 Play along with friends</li>
<li>✅ Have fun winning</li>
</ul>
<p><strong>Padel Time</strong> is available for <strong>free</strong> for <strong>iOS</strong> and <strong>watchOS</strong> devices and does provide a <strong>monthly</strong> or <strong>yearly</strong> subscription plan that enables you to share the excitment with your fellow players in realtime, enhancing the experience for everyone involved.</p>
<table>
<thead>
<tr>
<th style="text-align:center"><img src="/issues/issue1/watch1.webp" alt="Watch 1"></th>
<th style="text-align:center"><img src="/issues/issue1/watch2.webp" alt="Watch 2"></th>
<th style="text-align:center"><img src="/issues/issue1/watch3.webp" alt="Watch 3"></th>
</tr>
</thead>
</table>
<p>When your friends join your game by inserting your match session code, they will see the score update on their watch in <strong>realtime</strong>.
A must-have feature for non-stop <strong>Padel</strong> competitions 🏆.</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
        </item>
        <item>
            <title><![CDATA[Welcome to the iOS Coffee Break Newsletter 🎉]]></title>
            <link>https://www.ioscoffeebreak.com/issue/issue0</link>
            <guid>0</guid>
            <pubDate>Mon, 13 May 2024 09:20:00 GMT</pubDate>
            <description><![CDATA[iOS Coffee Break Newsletter is an exclusive monthly hand-curated newsletter showcasing the best articles, news, tips and apps from iOS developers worldwide.]]></description>
            <content:encoded><![CDATA[<p><strong>iOS Coffee Break</strong> is an exclusive weekly newsletter showcasing the best articles, news, tips and apps submitted by <strong>iOS</strong> developers worldwide.</p>
<p>My mission is to showcase the work of <strong>iOS</strong> developers by providing a platform for them to share their articles and their side projects.</p>
<p>Every <strong>month</strong>, I will provide you with a list of high valuable <strong>resources</strong> as well as interesting <strong>apps</strong> submitted by the community.
Everyone is welcome to submit articles or apps for free consideration.
To submit content, users will be invited to log in, where they will have access to their dashboard.</p>
<p>I will <strong>review</strong> and <strong>evaluate</strong> each <strong>submission</strong> and decide what shall be published each month. I may opt to find another way to decide what will be published in the future.
In the meantime, feel free to reach me out with suggestions!</p>
<p>My goal is to create a platform 100% fed by the <strong>iOS</strong> commmunity 💛.</p>
<p><strong>Subscribe</strong> if you would like to stay up to date and receive emails when new content is published!</p>
]]></content:encoded>
            <author>info.ioscoffeebreak@gmail.com (Tiago Henriques)</author>
            <category>Others</category>
            <enclosure url="https://raw.githubusercontent.com/henriquestiagoo/ioscoffeebreak-ci/main/issues/0.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>