<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Strongly Typed on Daniel Lyons</title><link>https://dandylyons.net/posts/</link><description>Recent content in Strongly Typed on Daniel Lyons</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><lastBuildDate>Thu, 01 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://dandylyons.net/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Adding Privacy-Friendly Comments to a Hugo Site with Chirpy</title><link>https://dandylyons.net/posts/adding-chirpy-comments/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/adding-chirpy-comments/</guid><description>&lt;p>I needed a comment system for this blog. Not because I expect a flood of discussion (let&amp;rsquo;s be honest, most personal tech blogs don&amp;rsquo;t) but because those rare moments when someone has a question or insight are worth enabling. The challenge? Finding a solution that respects privacy, stays free or cheap, and doesn&amp;rsquo;t require a PhD in server administration.&lt;/p>
&lt;h2 id="the-search-what-i-actually-needed">The Search: What I Actually Needed&lt;/h2>
&lt;p>My requirements were straightforward:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Privacy-preserving&lt;/strong> - No aggressive tracking or data selling&lt;/li>
&lt;li>&lt;strong>No account required&lt;/strong> - Reduce friction for commenters&lt;/li>
&lt;li>&lt;strong>Anonymous commenting&lt;/strong> - Allow users to comment without revealing their identity&lt;/li>
&lt;li>&lt;strong>Free or cheap&lt;/strong> - This is a personal blog, not a business&lt;/li>
&lt;li>&lt;strong>Proper moderation&lt;/strong> - I need to delete spam and get notified of new comments&lt;/li>
&lt;li>&lt;strong>Simple setup&lt;/strong> - Ideally just drop in a script tag&lt;/li>
&lt;li>&lt;strong>Future flexibility&lt;/strong> - Open source preferred, so I could self-host later if needed&lt;/li>
&lt;/ol>
&lt;h2 id="why-not-disqus">Why Not Disqus?&lt;/h2>
&lt;p>I tried &lt;a href="https://disqus.com">Disqus&lt;/a> first. It&amp;rsquo;s the obvious choice. It&amp;rsquo;s nearly ubiquitous, feature-rich, and easy to set up. But the more I learned about its privacy practices, the less comfortable I felt.&lt;/p></description></item><item><title>Ensuring Swift Compatibility on Linux</title><link>https://dandylyons.net/posts/ensuring-swift-compatibility-on-linux/</link><pubDate>Sat, 13 Dec 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/ensuring-swift-compatibility-on-linux/</guid><description>&lt;h1 id="ensuring-swift-compatibility-on-linux">Ensuring Swift Compatibility on Linux&lt;/h1>
&lt;p>Swift has long had a reputation for being &lt;em>that iOS language&lt;/em>, but the truth is that Swift has had cross-platform Linux support for nearly a decade. It&amp;rsquo;s robust and battle-tested in production, powering web backends, microservices, and command-line tools. That being said, like any platform, Linux has its own quirks and best practices that differ slightly from development on Apple platforms. This guide covers essential tips and strategies to ensure your Swift projects run smoothly on Linux.&lt;/p></description></item><item><title>How to Publish Unlisted Posts in Hugo</title><link>https://dandylyons.net/posts/unlisted-posts-in-hugo/</link><pubDate>Mon, 18 Aug 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/unlisted-posts-in-hugo/</guid><description>&lt;h1 id="how-to-publish-unlisted-posts-in-hugo">How to Publish Unlisted Posts in Hugo&lt;/h1>
&lt;p>Sometimes you want to publish a blog post that&amp;rsquo;s accessible via direct URL but doesn&amp;rsquo;t appear in your site&amp;rsquo;s normal navigation or discovery mechanisms. This is useful for sharing draft content with specific people, creating landing pages, or publishing content that you want to keep semi-private.&lt;/p>
&lt;p>When creating unlisted posts, you typically have four main concerns:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Search Engine Visibility&lt;/strong>: You don&amp;rsquo;t want the post to appear in Google search results&lt;/li>
&lt;li>&lt;strong>Sitemap Inclusion&lt;/strong>: You don&amp;rsquo;t want it listed in your sitemap.xml&lt;/li>
&lt;li>&lt;strong>RSS Feed Inclusion&lt;/strong>: You don&amp;rsquo;t want it appearing in your RSS feeds&lt;/li>
&lt;li>&lt;strong>Site Listings&lt;/strong>: You don&amp;rsquo;t want it showing up on any list pages (homepage recent posts, category pages, tag pages, etc.)&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s address each of these concerns systematically.&lt;/p></description></item><item><title>Migrating Notes from Hugo/Quartz to Obsidian Publish</title><link>https://dandylyons.net/posts/migrating-notes-from-hugo-quartz-to-obsidian-publish/</link><pubDate>Fri, 30 May 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/migrating-notes-from-hugo-quartz-to-obsidian-publish/</guid><description>&lt;h1 id="migrating-notes-from-obsidian-quartz-to-obsidian-publish-seamlessly-integrated-with-netlify">Migrating Notes from Obsidian Quartz to Obsidian Publish, Seamlessly Integrated with Netlify&lt;/h1>
&lt;p>It&amp;rsquo;s no secret that I am a very big fan of Obsidian. I use it for everything from note-taking to project management, and even as a publishing platform for my notes. In order to publish notes on the web, Obsidian offers &lt;a href="https://obsidian.md/publish">Obsidian Publish&lt;/a>, a service that allows you to host your notes as a static website. However, I had been using &lt;a href="https://quartz.jzhao.xyz/">Obsidian Quartz&lt;/a> for my publishing needs. I liked it primarily because it was free and open source, and I could host it myself on GitHub Pages. However, I found that the publishing workflow was a bit cumbersome. So I finally decided to migrate my notes from Obsidian Quartz to Obsidian Publish, while still keeping them under my main website (&lt;code>dandylyons.net&lt;/code>) using Netlify as a proxy.&lt;/p></description></item><item><title>Goodbye Dataview! Hello Obsidian Bases!</title><link>https://dandylyons.net/posts/goodbye-dataview-hello-obsidian-bases/</link><pubDate>Sat, 24 May 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/goodbye-dataview-hello-obsidian-bases/</guid><description>&lt;p>Obsidian has recently unveiled a game-changing native feature: &lt;strong>&lt;a href="https://help.obsidian.md/bases">Bases&lt;/a>&lt;/strong>. If you&amp;rsquo;ve ever wished for Notion-like database capabilities within your Obsidian vault, but with the security of open, human-readable formats that won&amp;rsquo;t lock you in, this is the update you&amp;rsquo;ve been waiting for. Bases, a new core plugin, is currently available for Catalyst members via early access (version 1.9.0 and above), and it&amp;rsquo;s set to revolutionize how we organize and interact with information in Obsidian.&lt;/p></description></item><item><title>Smooth Site Migration: Redirecting GitHub Pages to Netlify Path-by-Path (with Hugo &amp; SEO in Mind)</title><link>https://dandylyons.net/posts/smooth-site-migration-redirecting-github-pages-to-netlify-path-by-path/</link><pubDate>Wed, 14 May 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/smooth-site-migration-redirecting-github-pages-to-netlify-path-by-path/</guid><description>&lt;p>Migrating a website can be a bit like moving houses – exciting, but you still need to ensure everyone who knew your old address can find you at the new one. When I recently moved my personal site from GitHub Pages (&lt;code>dandylyons.github.io&lt;/code>) to Netlify (&lt;code>dandylyons.net&lt;/code>), I faced this exact challenge. My old GitHub Pages site was still live, and simply letting it sit there wasn&amp;rsquo;t ideal for users or search engine optimization (SEO).&lt;/p></description></item><item><title>Icons in SwiftUI</title><link>https://dandylyons.net/posts/icons-in-swiftui/</link><pubDate>Tue, 29 Apr 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/icons-in-swiftui/</guid><description>&lt;h1 id="icons-in-swiftui">Icons in SwiftUI&lt;/h1>
&lt;p>Icons are an incredibly powerful technique in modern UI design. They can convey meaning, add visual interest, and enhance the overall user experience. They can also take a lot of time to create and implement. Thankfully, SwiftUI comes with a built-in library of icons that you can use in your apps called SF Symbols. While SF Symbols are a fantastic resource, they still have a limited selection of icons (and very strict Apple guidelines). In this article, we’ll explore how to use SF Symbols in SwiftUI, we&amp;rsquo;ll learn about another open-source icon library, and finally we&amp;rsquo;ll learn how to create custom icons that fit your app’s design language.&lt;/p></description></item><item><title>Introducing: "Let There Be Sight" now in beta!</title><link>https://dandylyons.net/posts/let-there-be-sight-beta/</link><pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/let-there-be-sight-beta/</guid><description>&lt;h1 id="introducing-the-beta-of-let-there-be-sight-alt-text-made-easy">&lt;strong>Introducing the Beta of Let There Be Sight: Alt Text Made Easy&lt;/strong>&lt;/h1>
&lt;p>Today, I&amp;rsquo;m excited to announce the iOS beta release of my latest project: &lt;strong>Let There Be Sight&lt;/strong> — an app that makes it easy to describe any image with text. You can try it for free today via TestFlight:&lt;/p>
&lt;p>👉 &lt;a href="https://testflight.apple.com/join/E3uFbmZp">Join the beta on Apple TestFlight&lt;/a>&lt;/p>
&lt;p>But before you dive in, let me explain why this app matters.&lt;/p>
&lt;h2 id="why-alt-text-matters">Why Alt Text Matters&lt;/h2>
&lt;p>If you’ve spent any time in communities like Mastodon or Bluesky, you’ve probably seen people talking about the importance of alt text — short textual descriptions of images that make them accessible to people using screen readers.&lt;/p></description></item><item><title>Swift Error Handling: The Solution</title><link>https://dandylyons.net/posts/swift-error-handling-the-solution/</link><pubDate>Sat, 29 Mar 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-error-handling-the-solution/</guid><description>&lt;h1 id="swift-error-handling-the-solution">Swift Error Handling: The Solution&lt;/h1>
&lt;p>In our last post &lt;a href="https://dandylyons.net/posts/swift-error-handling-the-problem/">Swift Error Handling: The Problem&lt;/a> , we discussed the problems with error handling in Swift. In this post, we will explore some solutions to these problems and how to implement them in your code, and we will preview my new &lt;a href="https://swiftpackageindex.com/DandyLyons/Catcher">Catcher&lt;/a> library which provides a variety of tools following these patterns. 19|&lt;/p>
&lt;p>But alas, my library is not &lt;strong>the&lt;/strong> solution. It is only &lt;strong>a&lt;/strong> solution. In the last section, we will discuss some potential new Swift features that could eliminate these problems altogether.&lt;/p></description></item><item><title>Swift Error Handling: The Problem</title><link>https://dandylyons.net/posts/swift-error-handling-the-problem/</link><pubDate>Thu, 27 Mar 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-error-handling-the-problem/</guid><description>&lt;h1 id="swift-error-handling-the-problem">Swift Error Handling: The Problem&lt;/h1>
&lt;p>Error handling is a fundamental aspect of robust iOS application development. As developers, we&amp;rsquo;re constantly dealing with operations that can fail - network requests, file operations, data parsing, and user input validation. Swift provides a structured approach to error handling, but like any system, it has its strengths and weaknesses. In this first post of a three-part series, we&amp;rsquo;ll explore the current state of Swift&amp;rsquo;s error handling system, examining both what works well and what could be improved.&lt;/p></description></item><item><title>Actually Useful Obsidian: Formatting</title><link>https://dandylyons.net/posts/actually-useful-obsidian-formatting/</link><pubDate>Tue, 18 Feb 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/actually-useful-obsidian-formatting/</guid><description>&lt;p>Today we start a new series on one of my favorite note-taking apps, &lt;a href="https://obsidian.md/">Obsidian&lt;/a>. In this series, we&amp;rsquo;ll cover the basics of Obsidian. Here we will intentionally NOT be doing anything particularly fancy. We won&amp;rsquo;t be using strange plugins or custom CSS. Instead we&amp;rsquo;ll be focusing on the most helpul, core features that I use every day. Beginners will be able to finally overcome the initial learning curve and start using Obsidian effectively. And experienced users will find helpful tools to simplify their setup!&lt;/p></description></item><item><title>What's the difference between class and class_name in Godot?</title><link>https://dandylyons.net/posts/godot-class-vs-class_name/</link><pubDate>Tue, 11 Feb 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/godot-class-vs-class_name/</guid><description>&lt;p>When you&amp;rsquo;re writing scripts in Godot, you might have noticed that some scripts use &lt;code>class&lt;/code> and others use &lt;code>class_name&lt;/code>. What&amp;rsquo;s the difference between these two keywords? Let&amp;rsquo;s find out.&lt;/p>
&lt;h2 id="class_name-keyword">&lt;code>class_name&lt;/code> keyword&lt;/h2>
&lt;p>You may have noticed that so many GDScript scripts in Godot start with &lt;code>extends Node&lt;/code> or &lt;code>extends Resource&lt;/code>. This is because Godot uses a common programming feature called class inheritance.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript" data-lang="gdscript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">extends&lt;/span> &lt;span class="nc">Node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello, World!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So when you use &lt;code>extends&lt;/code>, you are telling GDScript that your class inherits from an existing class. So when we write &lt;code>extends Node&lt;/code>, we are creating a new class that inherits from the &lt;code>Node&lt;/code> class.&lt;/p></description></item><item><title>Easy Deep Copy Cloning in Swift</title><link>https://dandylyons.net/posts/easy-deep-copy-cloning-in-swift/</link><pubDate>Tue, 04 Feb 2025 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/easy-deep-copy-cloning-in-swift/</guid><description>&lt;p>In most programming languages, there is some concept of value and reference types. In Swift, we prefer to use value types and value semantics whenever possible. This is because value types are easier to reason about since they cannot be mutated by other parts of the code.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> However there are some times when we must use reference types. Is there a way to get our reference types to behave like value types? Yes, there is.&lt;/p></description></item><item><title>Introducing SelectiveEquatable</title><link>https://dandylyons.net/posts/selectiveequatable/</link><pubDate>Thu, 12 Dec 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/selectiveequatable/</guid><description>&lt;p>A few weeks ago, I released a blog post named &lt;a href="https://dandylyons.net/posts/post-24/selective-equality-checking-in-swift/">&amp;ldquo;Selective Equality Checking in Swift&amp;rdquo;&lt;/a>. In that post, I designed and implemented an API to check for equality on specific properties of a type. Today, I am excited to announce a new Swift protocol named &lt;code>SelectiveEquatable&lt;/code>, that makes all of this even easier. Let&amp;rsquo;s see it in action.&lt;/p>
&lt;h2 id="using-selectiveequatable">Using SelectiveEquatable&lt;/h2>
&lt;p>To use the &lt;code>SelectiveEquatable&lt;/code> protocol, all you need to do is add a conformance to it like this:&lt;/p></description></item><item><title>Am I Using Swift 5 or 6?</title><link>https://dandylyons.net/posts/am-i-using-swift-5-or-6/</link><pubDate>Tue, 19 Nov 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/am-i-using-swift-5-or-6/</guid><description>&lt;p>Swift is in the middle of a transition from Swift 5 to Swift 6. This transition is not as simple as it may seem. In this post, we will discuss how to determine which version of Swift you are using. But first we need to clear up some misconceptions.&lt;/p>
&lt;ol>
&lt;li>We need to understand the difference between Swift 6 &lt;strong>the compiler&lt;/strong> and Swift 6 &lt;strong>the language mode&lt;/strong>.&lt;/li>
&lt;li>We need to understand how to determine which version of the Swift &lt;strong>compiler&lt;/strong> we are using.&lt;/li>
&lt;li>We need to understand how to determine which version of the Swift &lt;strong>language mode&lt;/strong> we are using.&lt;/li>
&lt;li>We need to understand how to opt in or out of Swift 5 or Swift 6 &lt;strong>language mode&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>Note:&lt;/strong> This post will be primarily concerned with the native Swift Package Manager. Xcode has been known to behave slightly differently than SPM, and this post does not exhaustively cover all the ways Xcode may differ. This post assumes that you know how to use SPM and particularly how to declare a Swift Package using a &lt;code>Package.swift&lt;/code> file. If you are not familiar with this, I recommend reading the &lt;a href="https://swift.org/package-manager/">Swift Package Manager Documentation&lt;/a>.&lt;/p></description></item><item><title>Gradual Static Typing in GDScript</title><link>https://dandylyons.net/posts/gradual-static-typing-in-gdscript/</link><pubDate>Wed, 13 Nov 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/gradual-static-typing-in-gdscript/</guid><description>&lt;p>Any time we learn a new programming language, one of the first things we tend to fixate on is the syntax. But in many ways syntax is actually less important. The syntax is effectively the UI of the programming language. It&amp;rsquo;s how the language &amp;ldquo;looks&amp;rdquo;. But learning a language also requires understanding how a language &amp;ldquo;works&amp;rdquo;.&lt;/p>
&lt;p>One of the first and most important things that we should learn about a programming language is its &lt;strong>type system&lt;/strong>.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p></description></item><item><title>Selective Equality Checking in Swift</title><link>https://dandylyons.net/posts/selective-equality-checking-in-swift/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/selective-equality-checking-in-swift/</guid><description>&lt;p>The humble &lt;code>Equatable&lt;/code> protocols is one of the most fundamental tools in Swift, but sometimes it is not always the best tool for the job. Last week we learned how to &lt;a href="https://dandylyons.net/posts/unordered-equality-checking-in-swift/">check equality for collections while ignoring order&lt;/a>. Today we will learn how to pick and choose exactly what properties we would like to check equality on. But first let&amp;rsquo;s talk about the problem:&lt;/p>
&lt;h2 id="why-not-just-use-equatable">Why Not Just Use Equatable&lt;/h2>
&lt;p>For the majority of use cases the best option is to just use the plain old &lt;code>==&lt;/code> operator. We get this operator automatically when a type conforms to &lt;code>Equatable&lt;/code>. However it&amp;rsquo;s not always easy conform to &lt;code>Equatable&lt;/code>. Here are some situations when it might not be feasible or even possible to conform to &lt;code>Equatable&lt;/code>.&lt;/p></description></item><item><title>Unordered Equality Checking in Swift</title><link>https://dandylyons.net/posts/unordered-equality-checking-in-swift/</link><pubDate>Tue, 29 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/unordered-equality-checking-in-swift/</guid><description>&lt;p>Have you ever needed to compare two arrays in Swift, but the order of elements doesn&amp;rsquo;t matter? I find this often happens to me when convert between an ordered type such as &lt;code>Array&lt;/code> and an unordered type such as &lt;code>Set&lt;/code> or &lt;code>Dictionary&lt;/code>. Today, we&amp;rsquo;ll explore how to implement &lt;strong>unordered equality checking&lt;/strong> in Swift, starting with the basics and working our way up to a flexible, protocol-based solution.&lt;/p>
&lt;h2 id="what-is-deep-equality">What is Deep Equality?&lt;/h2>
&lt;p>Before diving into unordered equality, let&amp;rsquo;s briefly discuss deep equality. Many programming languages struggle with deep equality comparisons. Take JavaScript, for example:&lt;/p></description></item><item><title>A Deep Dive into Value and Reference Types in Swift</title><link>https://dandylyons.net/posts/swift-value-reference-deep-dive/</link><pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-value-reference-deep-dive/</guid><description>&lt;p>Understanding how Swift handles memory and data is key to writing efficient, bug-free code. In this post, we&amp;rsquo;ll explore the differences between value and reference types, and more importantly, what value and reference &lt;strong>semantics&lt;/strong> mean in Swift. By the end, you&amp;rsquo;ll know how to think about these concepts when designing your own Swift code.&lt;/p>
&lt;h2 id="value-vs-reference-types">Value vs. Reference Types&lt;/h2>
&lt;p>Let’s start with an analogy that can help illustrate the difference between value and reference types: a library. Most libraries today have both physical books and digital books.&lt;/p></description></item><item><title>Swift Assertions Cheatsheet: How, Why, and When to Crash</title><link>https://dandylyons.net/posts/mastering-swift-assertions/</link><pubDate>Wed, 16 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/mastering-swift-assertions/</guid><description>&lt;center>
&lt;img src="https://i.imgflip.com/96ybn9.jpg" alt="Chaos Girl Meme: Swift watches while a house labeled `fatalError()` burns.">
&lt;/center>
&lt;p>As Swift developers, we have several assertion tools at our disposal. But how do we choose the right one for each situation? This blog post will explore the different types of assertions in Swift and provide a framework to help you decide which to use and when.&lt;/p>
&lt;h2 id="what-is-an-assertion">What is an assertion?&lt;/h2>
&lt;p>Essentially assertion is a way to check your program&amp;rsquo;s state at runtime. If the program is behaving correctly (i.e. if its state matches your expectation) then the assertion will do nothing. But if it is not behaving correctly, then &lt;strong>the app will crash&lt;/strong>. In other words, &lt;strong>assertions in Swift are a way to crash your program on purpose&lt;/strong>.&lt;/p></description></item><item><title>Exhaustive, Flexible, Multi-Typed Error Handling in Swift</title><link>https://dandylyons.net/posts/typed-error-handling/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/typed-error-handling/</guid><description>&lt;p>Swift has long had fantastic error handling! Errors are simple value types that conform to the &lt;code>Error&lt;/code> protocol.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">struct&lt;/span> &lt;span class="nc">IceCreamShop&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">enum&lt;/span> &lt;span class="nc">Error&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Swift&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Error&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">notEnoughMoney&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">flavorNotSoldHere&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">set&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kd">var&lt;/span> &lt;span class="nv">availableFlavors&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IceCreamFlavor&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">set&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kd">var&lt;/span> &lt;span class="nv">cashOnHand&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">Int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">set&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kd">var&lt;/span> &lt;span class="nv">isFreezerOn&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">set&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kd">var&lt;/span> &lt;span class="nv">billLastPaidOn&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I really like this pattern! Here, we define a new error type that conforms to the &lt;code>Error&lt;/code> protocol. The definition feels a little strange but the call site is very nice. Normally we would simply conform a type to &lt;code>Error&lt;/code> but our type is also called &lt;code>Error&lt;/code> so we have to disambiguate. We define an enum type named &lt;code>Error&lt;/code> and it conforms to the &lt;code>Swift.Error&lt;/code> protocol (the &lt;code>Error&lt;/code> protocol from the Swift standard library). Why go to this trouble? Because the nested type makes the purpose very clear. In the outside world we can refer to the type as &lt;code>IceCreamShop.Error&lt;/code>, and inside the type we can call it &lt;code>Self.Error&lt;/code>. So it is very clear that &lt;code>IceCreamShop.Error&lt;/code> is designed to contain all the possible errors of the &lt;code>IceCreamShop&lt;/code> type. However, this is just a naming convention and nothing in the compiler enforces which types of errors can be thrown.&lt;/p></description></item><item><title>How to Visualize a Dependency Graph of Swift Dependencies</title><link>https://dandylyons.net/posts/swift-dependency-graph-visualization/</link><pubDate>Wed, 02 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-dependency-graph-visualization/</guid><description>&lt;p>As projects grow in complexity, it is common to use two techniques:&lt;/p>
&lt;ol>
&lt;li>Depend on external libraries.&lt;/li>
&lt;li>Split your codebase into multiple smaller modules.&lt;/li>
&lt;/ol>
&lt;p>These techniques have a number of benefits including:&lt;/p>
&lt;ol>
&lt;li>You can reduce build times by only building select modules, instead of the entire project.&lt;/li>
&lt;li>You can reuse modules in other projects.&lt;/li>
&lt;li>Swift forces you to define external APIs with the &lt;code>public&lt;/code> keyword, thus enforcing best practices.&lt;/li>
&lt;/ol>
&lt;p>But a modularized codebase also increases complexity by creating a web of dependencies. Small changes in one module, can have vast ripple effects down the dependency chain. For this reason, it can be immensely helpful to visualize your dependency graph like this.&lt;/p></description></item><item><title>Abstractions Increase Complexity: Here's Why That's Not A Bad Thing</title><link>https://dandylyons.net/posts/abstractions-increase-complexity/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/abstractions-increase-complexity/</guid><description>&lt;p>I&amp;rsquo;m starting to see a pattern that seems to replay again and again. A shiny new technology comes out that solves a problem. A bunch of developers flock to it, evangelizing it to everyone else. Eventually the tech disappoints. The developers complain that the new solution is so complicated, and they long for the next shiny new thing.&lt;/p>
&lt;p>Surely this pattern has existed for a long time, and will continue to repeat. But why does it happen? I think it&amp;rsquo;s because we have fallen for a fallacy. The fallacy is this:&lt;/p></description></item><item><title>The Swift Ranges Cheatsheet</title><link>https://dandylyons.net/posts/swift-ranges-cheatsheet/</link><pubDate>Wed, 25 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-ranges-cheatsheet/</guid><description>&lt;p>Ranges are fantastic for when we want to work with a range of sorted values that contain no duplicates.&lt;/p>
&lt;h2 id="core-concepts">Core Concepts:&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Ranges&lt;/strong> in Swift define a sequence of values between two bounds (lower and upper) and are widely used in loops, slicing collections, and pattern matching.&lt;/li>
&lt;li>There are different types of ranges that control whether the bounds are included or excluded.&lt;/li>
&lt;li>&lt;strong>Pattern Matching&lt;/strong>: Ranges can be used in &lt;code>switch&lt;/code> statements or &lt;code>if&lt;/code> conditions to check if a value falls within a specific range.&lt;/li>
&lt;li>&lt;strong>Comparable&lt;/strong>: Ranges must hold a &lt;code>Comparable&lt;/code> type.&lt;/li>
&lt;li>Prefer ranges when you want to work with a &lt;strong>sequence of values&lt;/strong> without storing the elements in memory, unlike an &lt;strong>array&lt;/strong> that holds all its values.&lt;/li>
&lt;/ul>
&lt;h2 id="range-types-side-by-side">Range Types Side by Side:&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;strong>Syntax&lt;/strong>&lt;/th>
&lt;th>&lt;strong>Range Type&lt;/strong>&lt;/th>
&lt;th>&lt;strong>Description&lt;/strong>&lt;/th>
&lt;th>&lt;strong>Lower Bound (✅/❌)&lt;/strong>&lt;/th>
&lt;th>&lt;strong>Upper Bound (✅/❌)&lt;/strong>&lt;/th>
&lt;th>&lt;strong>Includes Upper Bound (✅/❌)&lt;/strong>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>a..&amp;lt;b&lt;/code>&lt;/td>
&lt;td>&lt;code>Range&lt;/code>&lt;/td>
&lt;td>Half-open range; includes lower bound, excludes upper bound&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>a...b&lt;/code>&lt;/td>
&lt;td>&lt;code>ClosedRange&lt;/code>&lt;/td>
&lt;td>Closed range; includes both lower and upper bounds&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>a...&lt;/code>&lt;/td>
&lt;td>&lt;code>PartialRangeFrom&lt;/code>&lt;/td>
&lt;td>Range with only a lower bound&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>...b&lt;/code>&lt;/td>
&lt;td>&lt;code>PartialRangeThrough&lt;/code>&lt;/td>
&lt;td>Range with only an upper bound, includes upper bound&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>..&amp;lt;b&lt;/code>&lt;/td>
&lt;td>&lt;code>PartialRangeUpTo&lt;/code>&lt;/td>
&lt;td>Range with only an upper bound, excludes upper bound&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>...&lt;/code>&lt;/td>
&lt;td>&lt;code>UnboundedRange&lt;/code>&lt;/td>
&lt;td>Range without any bounds&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>❌&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="common-use-cases">Common Use Cases:&lt;/h2>
&lt;h3 id="iteration">Iteration:&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="mf">0.&lt;/span>&lt;span class="p">.&amp;lt;&lt;/span>&lt;span class="mi">5&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// Outputs 0 to 4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="pattern-matching">Pattern Matching:&lt;/h3>
&lt;p>Ranges are great to use in &lt;code>switch&lt;/code> or &lt;code>if-case&lt;/code> conditions to check if a value lies in a range.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p></description></item><item><title>Swift 6's New @retroactive Attribute</title><link>https://dandylyons.net/posts/swift-6-retroactive-attribute/</link><pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-6-retroactive-attribute/</guid><description>&lt;p>Swift 6.0 introduced the &lt;code>@retroactive&lt;/code> attribute to address a specific issue with protocol conformances. Here&amp;rsquo;s what you need to know:&lt;/p>
&lt;h2 id="the-problem">The Problem&lt;/h2>
&lt;p>Suppose you are using a type from an external library and realize that the type does not conform to a protocol such as &lt;code>Codable&lt;/code>. You might be tempted to add your own conformance.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">import&lt;/span> &lt;span class="nc">ExternalLibrary&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">extension&lt;/span> &lt;span class="nc">ExternalType&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Codable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// implementation here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>However, doing this can be quite problematic. What happens if the library owner later adds their own conformance? Which code will execute? Your conformance or their conformance? The answer is that the behavior will be undefined at runtime, since we don&amp;rsquo;t know which conformance will &amp;ldquo;win&amp;rdquo;. Even worse, this same problem will propagate to every library that imports your library.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/p></description></item><item><title>Demystifying Modern macOS Development</title><link>https://dandylyons.net/posts/demystifying-modern-macos-development/</link><pubDate>Mon, 23 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/demystifying-modern-macos-development/</guid><description>&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>For many years Apple, arguably left the Mac to languish for years while it focused on iOS and the iPhone. The Mac repeatedly got features years later than its mobile cousins, and the hardware was often behind and underpowered. But now, Mac app development is currently in the best state that it has been in a very long time, thanks to three major developments:&lt;/p>
&lt;ol>
&lt;li>Apple released &lt;a href="https://developer.apple.com/mac-catalyst/">Catalyst&lt;/a>, which translates iPad apps into native macOS apps.&lt;/li>
&lt;li>SwiftUI&amp;rsquo;s &lt;em>learn once, apply anywhere&lt;/em> design has made it dramatically easier to share code between macOS and iOS&lt;/li>
&lt;li>Apple silicon allows us to run iOS apps natively on the Mac without even translating.&lt;/li>
&lt;/ol>
&lt;p>The good news is that we&amp;rsquo;ve never had so many powerful, first-party supported ways to develop Mac apps. &lt;strong>The not so good news is that it&amp;rsquo;s never been so confusing.&lt;/strong> Today we will dive into the subtle differences between each of these approaches.&lt;/p></description></item><item><title>Benchmarking in Swift with swift-collections-benchmark</title><link>https://dandylyons.net/posts/benchmarking-in-swift-with-swift-collections-benchmark/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/benchmarking-in-swift-with-swift-collections-benchmark/</guid><description>&lt;p>There is an age-old adage of programming which states &lt;em>&amp;ldquo;Make it work, then make it right, then make it fast.&amp;rdquo;&lt;/em> Today we will be focusing on how to &lt;em>make it fast&lt;/em>, with the help of a valuable technique called Benchmarking.&lt;/p>
&lt;p>When developing software, especially when working with algorithms and data structures, performance is often a key concern. You may have experienced a piece of code that behaves well in your tests, but when it&amp;rsquo;s exposed to real-world data, performance degrades. This is where &lt;strong>benchmarking&lt;/strong> comes in. Benchmarking allows developers to measure how long a piece of code takes to run, helping to identify bottlenecks and areas for optimization.&lt;/p></description></item><item><title>Using Custom Components in Swift's Regex</title><link>https://dandylyons.net/posts/using-custom-components-in-swifts-regex/</link><pubDate>Tue, 10 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/using-custom-components-in-swifts-regex/</guid><description>&lt;p>In our &lt;a href="https://dandylyons.net/posts/the-many-faces-of-swifts-regex/">last article&lt;/a> we learned about Swift&amp;rsquo;s &lt;code>Regex&lt;/code> type and the various different ways to create them. Today we&amp;rsquo;re going to dive a little deeper into one of those methods. We&amp;rsquo;ll be building a custom &lt;code>RegexComponent&lt;/code> using the &lt;a href="https://developer.apple.com/documentation/swift/customconsumingregexcomponent">CustomConsumingRegexComponent&lt;/a> protocol.&lt;/p>
&lt;p>For a quick refresher, remember that we can create a custom parser using the &lt;code>RegexBuilder&lt;/code> DSL like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">import&lt;/span> &lt;span class="nc">RegexBuilder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nc">Regex&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Capture&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Repeat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">One&lt;/span>&lt;span class="p">(.&lt;/span>&lt;span class="n">digit&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;-&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Capture&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Repeat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">One&lt;/span>&lt;span class="p">(.&lt;/span>&lt;span class="n">digit&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;-&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Capture&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Repeat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">count&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">One&lt;/span>&lt;span class="p">(.&lt;/span>&lt;span class="n">digit&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Don&amp;rsquo;t forget that we can use many built-in parsers provided by &lt;code>Foundation&lt;/code> like this:&lt;/p></description></item><item><title>The Many Faces Of Swift's Regex</title><link>https://dandylyons.net/posts/the-many-faces-of-swifts-regex/</link><pubDate>Tue, 03 Sep 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/the-many-faces-of-swifts-regex/</guid><description>&lt;p>In Swift 5.7, Swift added native support for &lt;a href="https://en.wikipedia.org/wiki/Regular_expression">regular expressions&lt;/a> through a new type, &lt;a href="https://developer.apple.com/documentation/swift/regex">Regex&lt;/a>. Regular expressions have been a staple part of programming for decades and provide many capabilities including:&lt;/p>
&lt;ol>
&lt;li>data detection&lt;/li>
&lt;li>data validation&lt;/li>
&lt;li>string parsing&lt;/li>
&lt;/ol>
&lt;!-- >## To capture or not to capture?
>
>Brief aside, which will be important later: let's talk about the differences between detection, validation and parsing. **Detection** is finding if something is there (and where it is). For example, _is there a phone number in this string?_ **Validation** is determining if the string is a valid form of that data type. For example, _is 12-3456 a valid phone number?_ Finally, **parsing** is reading a string, and interpreting it as structured data. For example, _what is the area code, country code, and main part of the phone number?_ -->
&lt;p>However, regular expressions can also be notoriously difficult to use due to:&lt;/p></description></item><item><title>Using Optionals with SwiftUI Bindings</title><link>https://dandylyons.net/posts/using-optionals-with-swiftui-bindings/</link><pubDate>Tue, 27 Aug 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/using-optionals-with-swiftui-bindings/</guid><description>&lt;p>&lt;a href="https://developer.apple.com/documentation/swift/optional">Optionals&lt;/a> are an invaluable, core feature of Swift, and &lt;a href="https://developer.apple.com/documentation/swiftui/binding">Bindings&lt;/a> are the same for SwiftUI, but unfortunately it can be difficult to get them to play nicely with each other. Bindings are one of the core ways to empower child views to talk to parent views, and they are used throughout the SwiftUI framework. For example all of these core components use Bindings.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="n">TextField&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Last name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">$&lt;/span>&lt;span class="n">person&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lastName&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DatePicker&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Death date&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">selection&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">$&lt;/span>&lt;span class="n">person&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">deathDate&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ColorPicker&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Favorite color&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">selection&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">$&lt;/span>&lt;span class="n">person&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">favoriteColor&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But this gets much more complicated if you need a &lt;code>Binding&lt;/code> for an &lt;code>Optional&lt;/code> property. SwiftUI rarely, if ever, provides Views that accept an Optional Binding.&lt;/p></description></item><item><title>Exhaustive Testing Made Easy</title><link>https://dandylyons.net/posts/exhaustive-testing-made-easy/</link><pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/exhaustive-testing-made-easy/</guid><description>&lt;p>Testing is vitally important in virtually any tech stack. That is, unless you want to &lt;a href="https://en.wikipedia.org/wiki/2024_CrowdStrike_incident">shut down 8.5 million computers worldwide&lt;/a>. &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Testing is more than a tedious chore. It&amp;rsquo;s an automated warning system of current bugs. What is not automated (at least not entirely) is writing the tests. It takes time to write tests, and we have to know what needs to be tested. No matter how well your tests are written, if your tests don&amp;rsquo;t cover a particular situation, then it won&amp;rsquo;t be caught. This means that we need to assert on every value in our code. This is tedious and error-prone.&lt;/p></description></item><item><title>How to Take Full Advantage of Swift Package Index</title><link>https://dandylyons.net/posts/spi-tips/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/spi-tips/</guid><description>&lt;p>The &lt;a href="https://swiftpackageindex.com">Swift Package Index&lt;/a> (SPI) is an invaluable resource for both package users and maintainers, streamlining the process of discovering, using, and managing Swift packages. Whether you&amp;rsquo;re looking to integrate a package into your project or contribute your own, SPI offers a range of features to maximize your productivity and collaboration. This blog post will guide you through the best practices for leveraging SPI to its full potential.&lt;/p>
&lt;h2 id="tips-for-package-users">Tips for Package Users&lt;/h2>
&lt;h3 id="how-to-open-spi-from-github">How to Open SPI From GitHub&lt;/h3>
&lt;p>Perhaps you&amp;rsquo;ve already found a package you like on GitHub. You can easily jump to viewing the package on SPI simply by changing the url to &lt;code>swiftpackageindex.com&lt;/code>. For example, if you are currently at the GitHub repo for the new &lt;a href="https://github.com/swiftlang/swift-testing">Swift Testing&lt;/a> framework at &lt;a href="https://github.com/swiftlang/swift-testing">https://github.com/swiftlang/swift-testing&lt;/a> then simply change the url to &lt;a href="https://swiftpackageindex.com/swiftlang/swift-testing">https://swiftpackageindex.com/swiftlang/swift-testing&lt;/a>. If the package is already indexed on SPI then it will take you to the page. If not, then it will guide you through an easy process to request adding it to SPI.&lt;/p></description></item><item><title>Boost Your Productivity with These macOS Typing Shortcuts</title><link>https://dandylyons.net/posts/macos-typing-shortcuts/</link><pubDate>Tue, 06 Aug 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/macos-typing-shortcuts/</guid><description>&lt;p>Mastering keyboard shortcuts can significantly enhance your productivity on macOS. These shortcuts are versatile and work in nearly any text field across various macOS apps, including browsers. Moreover, many of these shortcuts can be combined, offering even more powerful text navigation and editing capabilities.&lt;/p>
&lt;blockquote>
&lt;h4 id="bonus-vim-equivalents">[BONUS] Vim Equivalents:&lt;/h4>
&lt;p>Many power users and coders may be familiar with Vim, which is a powerful text editor. All of these features are already available in Vim, or any editor that supports Vim key bindings, but if you are using an app that does not support Vim key bindings, then you do not have access to those features. On the other hand, the keyboard shortcuts, below, are available in almost every app in macOS. Non-Vim users can experience many (definitely not all) of the powerful features that Vim users already enjoy, except across the operating system, and without the obtuse syntax. For learning purposes, I&amp;rsquo;ll include the Vim equivalents in this article.&lt;/p></description></item><item><title>How to Scroll to a Percentage in a ScrollView</title><link>https://dandylyons.net/posts/scroll-to-percentage-in-scrollview/</link><pubDate>Tue, 30 Jul 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/scroll-to-percentage-in-scrollview/</guid><description>&lt;p>SwiftUI can make many tasks extremely easy, yet SwiftUi struggles to do other seemingly simple tasks. Today we will learn how to accomplish one of those tasks. We will create a ScrollView that can programmatically scroll to a specific location within the ScrollView. First let&amp;rsquo;s create a new type called &lt;code>ProgrammaticScrollView&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">struct&lt;/span> &lt;span class="nc">ProgrammaticScrollView&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">View&lt;/span>&lt;span class="p">&amp;gt;:&lt;/span> &lt;span class="n">View&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">@&lt;/span>&lt;span class="n">Binding&lt;/span> &lt;span class="kd">private&lt;/span> &lt;span class="kd">var&lt;/span> &lt;span class="nv">scrollID&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">Int&lt;/span>&lt;span class="p">?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">let&lt;/span> &lt;span class="nv">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">-&amp;gt;&lt;/span> &lt;span class="n">Content&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scrollID&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Binding&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nb">Int&lt;/span>&lt;span class="p">?&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">@&lt;/span>&lt;span class="n">ViewBuilder&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">@&lt;/span>&lt;span class="n">escaping&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">-&amp;gt;&lt;/span> &lt;span class="n">Content&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kc">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">_scrollID&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">scrollID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kc">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">content&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">content&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nv">body&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">some&lt;/span> &lt;span class="n">View&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ScrollView&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ForEach&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">1.&lt;/span>&lt;span class="p">.&amp;lt;&lt;/span>&lt;span class="mi">101&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="k">in&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">VStack&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">\(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="si">)&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">frame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">maxWidth&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">infinity&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">alignment&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">leading&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Spacer&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">scrollPosition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">$&lt;/span>&lt;span class="n">scrollID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">anchor&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">top&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here we&amp;rsquo;re using iOS 17&amp;rsquo;s new &lt;a href="https://developer.apple.com/documentation/swiftui/view/scrollposition%28id:anchor:%29">scrollPosition(id: anchor:)&lt;/a> method. This method receives an &lt;code>id&lt;/code> of type &lt;code>Binding&amp;lt;(some Hashable)?&amp;gt;&lt;/code> and then scrolls to a child view with that id. As you can see there are 100 child views numbered 1 to 100, each with a corresponding id. Programmatically scrolling is now as simple as changing the value of our scrollID Binding!&lt;/p></description></item><item><title>Hello Hugo</title><link>https://dandylyons.net/posts/hello-hugo/</link><pubDate>Tue, 23 Jul 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/hello-hugo/</guid><description>&lt;p>Hello!&lt;/p>
&lt;p>Welcome to my personal site! Here I will be posting my projects and things I&amp;rsquo;m learning.&lt;/p>
&lt;p>I&amp;rsquo;ve recently rewritten this site in &lt;a href="https://gohugo.io/">hugo&lt;/a>! I appreciate how blazingly fast and customizable it is. The code for this site can be found &lt;a href="https://github.com/DandyLyons/DandyLyons.github.io">here&lt;/a>.&lt;/p>
&lt;h2 id="dev-diary">Dev Diary&lt;/h2>
&lt;p>Now I&amp;rsquo;d like to share some of my journey of creating this site.&lt;/p>
&lt;p>When creating this site, I had a few priorities:&lt;/p>
&lt;ol>
&lt;li>It should be statically generated.&lt;/li>
&lt;li>It should be easy to write on using Markdown.&lt;/li>
&lt;li>It should be customizable.&lt;/li>
&lt;li>It should support modern &amp;ldquo;tablestakes&amp;rdquo; website features. (dark mode, social previews, favicons etc.)&lt;/li>
&lt;li>It should be developed in Swift.&lt;/li>
&lt;/ol>
&lt;h3 id="initial-priorities">Initial Priorities&lt;/h3>
&lt;h4 id="it-should-be-statically-generated">It should be statically generated&lt;/h4>
&lt;p>One of my first encounters with the concept of statically generated sites was &lt;a href="https://www.swiftbysundell.com">Swift by Sundell&lt;/a>. This has been one of my favorite blogs for years, and so eventually I learned that John Sundell created his site using something called Static Site Generation, which is when the entire site generated ahead of time statically.&lt;/p></description></item><item><title>Concrete and "Soft" Types in Swift</title><link>https://dandylyons.net/posts/swift-generics/concrete-types-swift/</link><pubDate>Mon, 01 Apr 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-generics/concrete-types-swift/</guid><description>&lt;p>In our &lt;a href="https://dandylyons.net/posts/swift-generics/explicit-types-swift/">last article&lt;/a>, we learned about how the generics system is deeply integrated into Swift at practically every level. This can give us magical features that help like &lt;em>Type Inference&lt;/em> which makes our code easier to read and right, but it can also lead frustrating and confusing compile-time errors. Furthermore, most modern Swift libraries are filled with generic code, especially in Apple first-party frameworks such as &lt;strong>SwiftUI&lt;/strong>, &lt;strong>Combine&lt;/strong>, and the recently announced &lt;strong>SwiftData&lt;/strong>. I hope that I&amp;rsquo;ve made a strong case that &lt;strong>generics in Swift are simply too important to ignore&lt;/strong>. So without further ado, let&amp;rsquo;s dive into generics, albeit with a slightly different approach than you might expect.&lt;/p></description></item><item><title>Explicit and Implicit Types in Swift</title><link>https://dandylyons.net/posts/swift-generics/explicit-types-swift/</link><pubDate>Sat, 16 Mar 2024 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/swift-generics/explicit-types-swift/</guid><description>&lt;p>Generics are one of the most powerful features in Swift, yet they can often feel overwhelming, even for seasoned Swift developers. In this series we&amp;rsquo;ll learn how to make generics simple, useful, and even fun!&lt;/p>
&lt;h3 id="back-to-basics">Back to Basics&lt;/h3>
&lt;p>But to start off, we&amp;rsquo;ll look somewhere you probably won&amp;rsquo;t expect: declaring variables.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-swift" data-lang="swift">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nv">strings&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Paul&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;George&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Ringo&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nv">oneLongString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">strings&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">joined&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">separator&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s">&amp;#34;, &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This seemingly simple piece of code has some hidden functionality. Consider for a second, what type is &lt;code>strings&lt;/code>. That&amp;rsquo;s easy. It&amp;rsquo;s an &lt;code>Array&lt;/code>. But that answer is only half correct. Notice, how does &lt;code>strings&lt;/code> know about the &lt;code>joined&lt;/code> method? How does it know how to join the elements? What if that was an array of numbers?. Here, most Swift developers would say that the answer is &lt;a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/types/#Type-Inference">Type Inference&lt;/a>. And while that answer is technically correct, it&amp;rsquo;s still missing part of the story.&lt;/p></description></item><item><title>How to add Apple’s “Night Mode” to your SwiftUI Views</title><link>https://dandylyons.net/posts/implement-swiftui-night-mode/</link><pubDate>Thu, 14 Sep 2023 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/implement-swiftui-night-mode/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>Tip&lt;/strong>: Try the code for yourself!
If you like this, please try the Swift Package that I created called &lt;a href="https://dandylyons.net/projects/plusnightmode/">PlusNightMode&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>:
I originally posted this blog post to Medium, &lt;a href="https://medium.com/@_DandyLyons/how-to-add-apples-night-mode-to-your-swiftui-views-e172bb41dc94">here&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>Screens have propagated to practically every area of our lives and while that has been tremendously beneficial in many ways, it has led &lt;a href="https://healthmatch.io/blog/too-many-of-us-are-sleep-deprived-and-its-become-a-crisis#:~:text=Even%20with%20just%20one%20night,of%20chronic%20conditions%20and%20death.">chronic sleep issues&lt;/a>. To address this, Apple and the rest of the tech industry has slowly rolled out a variety of features to tackle this problem. First, there was &lt;a href="https://support.apple.com/en-us/HT207570">Night Shift&lt;/a>, &lt;a href="https://support.apple.com/en-us/HT210332">Dark Mode&lt;/a>, then &lt;a href="https://support.apple.com/en-us/HT208982">Screen Time&lt;/a>. Now in iOS 17, Apple has introduced “Night Mode”, except it’s not in it’s own feature. It’s buried inside of other features (&lt;a href="https://www.macrumors.com/how-to/use-standby-mode-iphone/">StandBy&lt;/a> on iPhone, and the &lt;a href="https://9to5mac.com/2023/06/07/apple-watch-ultra-auto-night-mode/">Wayfinder&lt;/a> watch face on Apple Watch Ultra).&lt;/p></description></item><item><title>How to use a JS for...of loop with an index</title><link>https://dandylyons.net/posts/js-for-of-loop/</link><pubDate>Thu, 07 Sep 2023 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/js-for-of-loop/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>:
I originally posted this blog post to Medium, &lt;a href="https://medium.com/@_DandyLyons/how-to-use-a-js-for-of-loop-with-an-index-a4675ed22351">here&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>JavaScript’s &lt;code>for...of&lt;/code> loop is a powerful construct for iterating over elements in an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#built-in_iterables">iterable&lt;/a>, such as arrays, strings, or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#built-in_iterables:~:text=iterables%20and%20iterators.-,Built%2Din%20iterables,-String%2C%20Array">other iterable objects&lt;/a>. However, unlike the traditional &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for">C-style for loop&lt;/a>, &lt;strong>the&lt;/strong> &lt;code>for...of&lt;/code> &lt;strong>loop doesn&amp;rsquo;t provide a built-in index&lt;/strong>. But fear not! In this blog post, we&amp;rsquo;ll learn how to use the &lt;code>for...of&lt;/code> loop with an index.&lt;/p>
&lt;h2 id="the-traditionalforofloop">The Traditional &lt;code>for...of&lt;/code> Loop&lt;/h2>
&lt;p>Before diving into adding an index, let’s quickly review how the standard &lt;code>for...of&lt;/code> loop works:&lt;/p></description></item><item><title>7 Ways to Organize SwiftUI Code</title><link>https://dandylyons.net/posts/7-ways-to-organize-swiftui-code/</link><pubDate>Thu, 06 May 2021 00:00:00 +0000</pubDate><guid>https://dandylyons.net/posts/7-ways-to-organize-swiftui-code/</guid><description>&lt;blockquote>
&lt;p>NOTE:
I originally posted this blog post to Medium, &lt;a href="https://medium.com/@_DandyLyons/7-ways-to-organize-swiftui-code-e786307d3916">here&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>SwiftUI is a complete paradigm shift in how we write apps for Apple platforms. It’s functional and declarative rather than object-oriented and imperative. And there is no need for ViewControllers anymore! While all of this means that we can write code that is more readable, testable, and reusable, it also means that we don’t have decades of tried and true architecture patterns to draw from.&lt;/p></description></item></channel></rss>