<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title> iOS Code Review | Curated code improvement tips</title>
<description type="html"><![CDATA[Bi-weekly newsletter amplifying code improvement tips from the Apple developer community in a bite-sized format. Swift, Objective-C, iOS, macOS, SwiftUI, UIKit and more. Curated and published every two weeks. ]]></description>
<link>https://ioscodereview.com</link>
<image>
    <url>https://ioscodereview.com/favicon.png</url>
    <title>iOS Code Review Newsletter</title>
    <link>https://ioscodereview.com</link>
</image>
<lastBuildDate>Wed, 15 Apr 2026 09:26:11 -0700</lastBuildDate>
<atom:link href="https://ioscodereview.com" rel="self" type="application/rss+xml"/>
<ttl>60</ttl>

    <item>
        <title><![CDATA[ Issue #77: Swift Is Bigger Than Xcode, a Paste Bug You&#x27;ve Probably Hit, and WWDC Is 57 Days Away ]]></title>
        <description><![CDATA[ Hey everyone! 👋

Short on time this week? Here&#39;s the TL;DR: Swift now works in basically every AI-native IDE, Xcode 26.4 has a really annoying paste bug with a simple workaround, the April 28 SDK deadline is this month, and a Swift-native game engine just dropped a ]]></description>
        <link>https://ioscodereview.com/issues/issue-77-swift-is-bigger-than-xcode-and-other-dev-updates/</link>
        <guid isPermaLink="false">69dde46dd6dad6000131daff</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 15 Apr 2026 09:20:56 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hey everyone! 👋</p><p>Short on time this week? Here's the TL;DR: Swift now works in basically every AI-native IDE, Xcode 26.4 has a really annoying paste bug with a simple workaround, the April 28 SDK deadline is <em>this month</em>, and a Swift-native game engine just dropped a proper release. Oh, and Deep Dish Swift wrapped up in Chicago a few days ago. Let's get into it. 🚀</p><hr><p><strong>Swift Is Now in (Almost) Every IDE</strong></p><p>As of April 8th, the official Swift extension for VS Code is now available on the Open VSX Registry, the vendor-neutral, open source extension registry hosted by the Eclipse Foundation. That means you can now write Swift in Cursor, VSCodium, AWS's Kiro, Google's Antigravity, and more, all without a manual download. <a href="https://www.swift.org/blog/expanding-swift-ide-support/?ref=ioscodereview.com">Swift</a></p><p>The extension brings code completion, refactoring, full debugging support, a test explorer, and DocC support to the entire ecosystem of VS Code-compatible editors. Agentic IDEs like Cursor and Antigravity can now automatically install Swift support when they detect a Swift project. <a href="https://www.infoworld.com/article/4157422/swift-for-visual-studio-code-comes-to-open-vsx-registry.html?ref=ioscodereview.com">InfoWorld</a></p><p>The bigger picture here is what iOS Dev Weekly's Dave Verwer put well this week: Swift is bigger than Xcode now. Android, Wasm, Windows, embedded hardware, and now every major AI IDE, the language has quietly become general-purpose in a way that would have seemed unlikely five years ago. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/expanding-swift-ide-support/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Expanding Swift’s IDE Support</div><div class="kg-bookmark-description">You can now write Swift in a broader range of popular IDEs, including Cursor, VSCodium, AWS’s Kiro, and Google’s Antigravity. By leveraging VS Code extension compatibility, these editors tap directly into the Open VSX Registry, where the official Swift extension is now live.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.ghost.org/v5.0.0/images/link-icon.svg" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swift.org/apple-touch-icon-180x180.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>PSA: Xcode 26.4 Broke Simulator Paste</strong></p><p>After updating to Xcode 26.4, pasting from your Mac into the iOS Simulator is completely broken. Cmd+V does nothing, long-pressing a text field shows no Paste option, and the Simulator's clipboard appears empty. Restarting the Simulator, toggling "Automatically Sync Pasteboard," and resetting privacy settings all fail to fix it. <a href="https://samwize.com/2026/03/30/xcode-simulator-paste-broken-workaround/?ref=ioscodereview.com">@samwize</a></p><p>The workaround, courtesy of Junda Ong:</p><p>bash</p><pre><code class="language-bash">echo -n "your text here" | xcrun simctl pbcopy booted</code></pre><p>This bypasses the broken Mac-to-Simulator auto-sync by writing directly to the Simulator's pasteboard. You still need to Cmd+V inside the Simulator after running it, but it works. <a href="https://samwize.com/2026/03/30/xcode-simulator-paste-broken-workaround/?ref=ioscodereview.com">@samwize</a></p><p>If running that command manually every time sounds tedious — it is. Junda followed up by vibe coding a small Mac app that keeps the two clipboards in sync automatically, using the one-liner <code>pbpaste | xcrun simctl pbcopy booted</code> under the hood. <a href="https://samwize.com/2026/04/04/i-vibe-coded-a-mac-app-to-fix-xcode-simulator-paste/?ref=ioscodereview.com">@samwize</a> Apple has acknowledged the bug and is working on a fix; Xcode 26.5 Beta is reportedly where to watch for the resolution.</p><p><a href="https://samwize.com/2026/03/30/xcode-simulator-paste-broken-workaround/?ref=ioscodereview.com">Workaround post</a> · <a href="https://samwize.com/2026/04/04/i-vibe-coded-a-mac-app-to-fix-xcode-simulator-paste/?ref=ioscodereview.com">The vibe-coded fix</a> · <a href="https://developer.apple.com/forums/thread/820393?ref=ioscodereview.com">Apple Developer Forums thread</a></p><hr><p><strong>⚠️ SDK Deadline: April 28 — Two Weeks Away</strong></p><p>You've seen this before, but it's worth repeating since it's now genuinely urgent. Starting April 28, 2026, all apps and games uploaded to App Store Connect must be built with the iOS 26 &amp; iPadOS 26 SDK or later. The same applies to tvOS 26, visionOS 26, and watchOS 26. <a href="https://developer.apple.com/news/?ref=ioscodereview.com">Apple Developer</a></p><p>If you haven't migrated to Xcode 26 yet, now is the time. The watchOS requirement also specifically mandates 64-bit support for Apple Watch Series 9, Series 10, and Apple Watch Ultra 2. Don't wait until April 27th.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/news/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Latest News - Apple Developer</div><div class="kg-bookmark-description">Learn about the latest technologies, events, and policies for developers.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.ghost.org/v5.0.0/images/link-icon.svg" alt=""><span class="kg-bookmark-author">Apple Developer</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-developer-og.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Untold Engine Studio: A Swift Game Engine Worth Watching</strong></p><p>Harold Serrano released Untold Engine Studio this week, the first bundled desktop release of the Untold Engine ecosystem. The goal is to remove friction: download a <code>.dmg</code>, and start building games immediately without cloning repos or setting up dependencies. <a href="https://www.haroldserrano.com/blog/?ref=ioscodereview.com">Harold Serrano</a></p><p>The engine is written in Swift and powered by Metal, supporting macOS, iOS, and visionOS. It uses an ECS-based gameplay model and includes Gaussian Splat Rendering that runs natively on Vision Pro hardware. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/untoldengine?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">untoldengine - Overview</div><div class="kg-bookmark-description">An easy to use, open source, 3D game engine for iOS/macOS game development. - untoldengine</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/pinned-octocat-093da3e6fa40.svg" alt=""><span class="kg-bookmark-author">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/13968584" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>It's code-driven rather than editor-first, so it's aimed at developers who want to understand and shape the underlying system.</p><p>Not trying to dethrone Unreal or Unity, just a well-crafted, native, Swift-first option that's been in development for over 12 years and is finally at a polished release point.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.haroldserrano.com/blog/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Blog - Harold Serrano | Game Engine Developer</div><div class="kg-bookmark-description">Interested in making a game engine from scratch? In these articles I share everything you need to know about game engine development.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.ghost.org/v5.0.0/images/link-icon.svg" alt=""><span class="kg-bookmark-author">Harold Serrano</span><span class="kg-bookmark-publisher">Harold Serrano</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/HaroldSerrano-Logo2.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Deep Dish Swift 2026 Wrapped Up This Weekend</strong></p><p>Deep Dish Swift hosted its fourth conference in Chicago this weekend, April 12–14, bringing together developers of all experience levels to share knowledge from a diverse set of speakers. <a href="https://deepdishswift.com/?ref=ioscodereview.com">Deepdishswift</a> Sessions will be published after the conference, so keep an eye on their YouTube channel if you missed it. A solid lineup this year, look out for the talks on indie development, structured concurrency, and Server-Side Swift.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://deepdishswift.com/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Deep Dish Swift 2026 | April 12th to 14th</div><div class="kg-bookmark-description">A supreme Swift developer conference being served in Chicago, Illinois</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.ghost.org/v5.0.0/images/link-icon.svg" alt=""><span class="kg-bookmark-author">April 12th to 14th</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/og_image_2026.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>WWDC 2026: June 8–12, Mark Your Calendar</strong></p><p>WWDC 2026 runs June 8–12. Apple will hold it primarily online, with select developers and students invited to Apple Park. 50 Distinguished Swift Student Challenge winners have been invited for a three-day experience in Cupertino, including the keynote on June 8. <a href="https://www.macrumors.com/roundup/wwdc/?ref=ioscodereview.com">MacRumors</a> This year, Apple has been teasing AI advancements as a central theme, expect iOS 27 and what comes next for the Foundation Models framework front and center.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.apple.com/newsroom/2026/03/apples-worldwide-developers-conference-returns-the-week-of-june-8/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Apple’s Worldwide Developers Conference returns the week of June 8</div><div class="kg-bookmark-description">Apple today announced it will host its annual Worldwide Developers Conference (WWDC) online from June 8-12.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.ghost.org/v5.0.0/images/link-icon.svg" alt=""><span class="kg-bookmark-author">Apple Newsroom</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/Apple-WWDC26-event-branding-lp.jpg.og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p>✌️ That's Issue #77! Big two weeks: Swift is everywhere now, fix your paste bug before it drives you crazy, and don't miss the April 28 deadline.</p><p>Let's get ready for WWDC season to kick into gear! 🚀</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #76: Swift 6.3 Is Here, Swift on Android, Smarter Tests &amp; One Very Important Date ]]></title>
        <description><![CDATA[ Hey everyone! 👋

What a time to be a Swift developer. Seriously.

Swift 6.3 dropped and it&#39;s packed, the official Android SDK is here, Swift Testing keeps leveling up, and the @c attribute finally makes C interoperability feel like a first-class citizen. Oh, and if you&#39;ve ]]></description>
        <link>https://ioscodereview.com/issues/issue-76-swift-6-3-is-here-swift-on-android-smarter-tests-one-very-important-date/</link>
        <guid isPermaLink="false">69cabdc6e0135900014ce2ec</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 30 Mar 2026 11:21:46 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hey everyone! 👋</p><p>What a time to be a Swift developer. Seriously.</p><p>Swift 6.3 dropped and it's packed, the official Android SDK is here, Swift Testing keeps leveling up, and the <code>@c</code> attribute finally makes C interoperability feel like a first-class citizen. Oh, and if you've been sleeping on the agentic coding features in Xcode 26.3, we're covering that too because it's genuinely worth your time.</p><p>We've also got a deadline reminder that you really don't want to miss (April 28 is closer than it feels), and a shoutout to this year's Swift Student Challenge winners who, as always, have shipped some seriously creative work.</p><p>Alright, let's get into it. 🚀</p><p><strong>Swift 6.3: Swift Testing Gets Smarter</strong></p><p>Swift 6.3 (released March 24) brings three handy improvements to Swift Testing. First, warning issues let you record a non-fatal issue without failing the test:</p><pre><code class="language-swift">Issue.record("Something suspicious happened", severity: .warning)</code></pre><p>Second, test cancellation lets you bail out mid-test gracefully — useful for skipping specific arguments in a parameterized test, or responding to conditions that make continuing pointless:</p><pre><code class="language-swift">try Test.cancel()</code></pre><p>And third, image attachments let you attach <code>UIImage</code>, <code>CGImage</code>, <code>CIImage</code>, or <code>NSImage</code> instances directly to your test reports for visual verification — especially handy for snapshot tests or Vision framework work. These are exposed via new cross-import overlay modules with UIKit and friends.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/swift-6.3-released/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift 6.3 Released</div><div class="kg-bookmark-description">Swift is designed to be the language you reach for at every layer of the software stack. Whether you’re building embedded firmware, internet-scale services, or full-featured mobile apps, Swift delivers strong safety guarantees, performance control when you need it, and expressive language features and APIs.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-180x180-2.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-touch-icon-180x180-2.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Swift 6.3: Swift Goes Android</strong></p><p>The headline feature of Swift 6.3: the first official Swift SDK for Android. With it you can write native Android apps in Swift, update existing Swift packages to support Android builds, and use <code>Swift Java</code> and <code>Swift Java JNI Core</code> to slot Swift code into apps already written in Kotlin or Java.</p><pre><code class="language-swift">// Swift code callable from an Android Kotlin app via Swift Java JNI Core
@_silgen_name("Java_com_example_MyApp_greet")
public func greet() -&gt; String {
    return "Hello from Swift on Android!"
}</code></pre><p>This doesn't mean Kotlin is going anywhere, it remains the primary language for Android development. But for teams already deep in Swift for iOS, this opens a path to sharing business logic across platforms without a rewrite.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/documentation/articles/swift-sdk-for-android-getting-started.html?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift.org</div><div class="kg-bookmark-description">Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-180x180-3.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-touch-icon-180x180-3.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Swift 6.3: The <code>@c</code> Attribute</strong></p><p>Swift 6.3 also formalizes the long-unofficial <code>@_cdecl</code> attribute into the new <code>@c</code> attribute, letting you expose Swift functions and enums directly to C code:</p><pre><code class="language-swift">@c public func MyLib_initialize() {
    // Swift implementation, callable from C
}</code></pre><p>When combined with <code>@implementation</code>, the compiler will validate that your Swift function's signature matches a pre-existing declaration in a C header — catching mismatches at compile time rather than surfacing them as cryptic "deserialization" failures at runtime.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/embedded-swift-improvements-coming-in-swift-6.3/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Embedded Swift Improvements Coming in Swift 6.3</div><div class="kg-bookmark-description">Embedded Swift is a subset of Swift that’s designed for low resource usage, making it capable of running on constrained environments like microcontrollers. Using a special compilation mode, Embedded Swift produces significantly smaller binaries than regular Swift. While a subset of the full language, the vast majority of the Swift language works exactly the same in Embedded Swift. Additional information is described in the Embedded Swift vision document.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-180x180-4.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-touch-icon-180x180-4.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Xcode 26.3: Agentic Coding</strong></p><p>If you haven't tried it yet, Xcode 26.3 shipped in late February and introduced agentic coding with Claude Agent and OpenAI Codex baked in. Rather than just suggesting completions, agents can now reason across your whole project: exploring file structures, updating settings, running builds, capturing Xcode Previews to verify UI, and iterating until tests pass.</p><p>You stay in control, the agent logs everything in a transcript, automatic milestones let you roll back any change without touching Git, and you can swap between agents mid-project depending on the task.</p><p>Any MCP-compatible agent can also plug in via the open Model Context Protocol, it's not just Claude and Codex.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.apple.com/newsroom/2026/02/xcode-26-point-3-unlocks-the-power-of-agentic-coding/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Xcode 26.3 unlocks the power of agentic coding</div><div class="kg-bookmark-description">Xcode 26.3 introduces support for agentic coding, a new way in Xcode for developers to build apps, powered by coding agents from Anthropic and OpenAI.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-6.ico" alt=""><span class="kg-bookmark-author">Apple Newsroom</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/Apple-Xcode-agentic-coding-hero-lp.jpg.og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>SDK Deadline: April 28</strong></p><p>Reminder, since it's coming up fast. Starting April 28, 2026, apps and games uploaded to App Store Connect need to be built with the iOS 26 &amp; iPadOS 26 SDK or later <a href="https://developer.apple.com/news/?ref=ioscodereview.com">Apple Developer</a> — same applies to tvOS, visionOS, and watchOS. If you haven't migrated to Xcode 26 yet, that clock is ticking.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/news/?id=ueeok6yw&ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Upcoming SDK minimum requirements - Latest News - Apple Developer</div><div class="kg-bookmark-description">Starting April 28, 2026, apps and games uploaded to App&nbsp;Store&nbsp;Connect need to meet the following minimum requirements:
iOS and iPadOS apps must be built with the iOS&nbsp;26&nbsp;&amp; iPadOS&nbsp;26&nbsp;SDK or&nbsp;later
tvOS apps must be built with the tvOS&nbsp;26&nbsp;SDK or&nbsp;later
visionOS apps must be built with the visionOS&nbsp;26&nbsp;SDK or&nbsp;later
watchOS apps must be built with the watchOS&nbsp;26&nbsp;SDK or&nbsp;later
Learn more about submitting</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-logo-2.svg" alt=""><span class="kg-bookmark-author">Apple Developer</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/ios-ipados-og-1.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Swift Student Challenge 2026 Winners</strong></p><p>Apple began notifying students who won the WWDC 2026 Swift Student Challenge this week. <a href="https://www.macrumors.com/2026/03/26/apple-swift-student-challenge-winners-2026/?ref=ioscodereview.com">MacRumors</a> Winners receive AirPods Max 2, a one-year Apple Developer membership, and a certificate. 50 Distinguished Winners will be invited to Apple Park for a three-day experience including the WWDC Special Event keynote on June 8. <a href="https://www.macrumors.com/2026/03/26/apple-swift-student-challenge-winners-2026/?ref=ioscodereview.com">MacRumors</a></p><p>Worth browsing the winners' submissions, they're always a great source of creative SwiftUI and Swift Playgrounds ideas.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/swift-student-challenge/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift Student Challenge</div><div class="kg-bookmark-description">Showcase your love of coding by submitting your app playground to the Swift Student Challenge.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-logo-3.svg" alt=""><span class="kg-bookmark-author">Apple Developer</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/ssc-26-og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p>✌️ That's a wrap for Issue #76! Big month for Swift, a new language version, the Android SDK landing officially, and agentic coding now stable in Xcode. Lots to explore.</p><p>As always, reply with what you want covered next. See you in two weeks! 🚀</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #75: We&#x27;re Back! Tool Calling, Default Actors &amp; the Clock Is Ticking ]]></title>
        <description><![CDATA[ Hey everyone! 👋

It&#39;s been a little while, hasn&#39;t it? First things first, a huge thank you to Marina for everything she&#39;s built here. She set an incredible foundation and this community is better for it. Big shoes to fill, but we&#39;re going ]]></description>
        <link>https://ioscodereview.com/issues/issue-75-were-back-tool-calling-default-actors-the-clock-is-ticking/</link>
        <guid isPermaLink="false">69b8f101ff3c6e00014f97aa</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 16 Mar 2026 23:28:33 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hey everyone! 👋</p><p>It's been a little while, hasn't it? First things first, a huge thank you to Marina for everything she's built here. She set an incredible foundation and this community is better for it. Big shoes to fill, but we're going to give it a shot.</p><p>I'm Sam, and I'll be taking the reins going forward. I've been a software engineer for 12+ years, 7 of those in the mobile space! I'm genuinely excited to be here. The plan is simple: keep delivering the good stuff, dig a little deeper on the topics that matter to you as iOS devs, and hopefully add a bit more value along the way.</p><p>This newsletter is for you, not me. So if there's something you want covered, a topic you've been nerding out on, or even just feedback on how we're doing, please reach out. Seriously. Reply to this email, find me online, whatever works. I want to hear from you.</p><p>Alright, enough from me, let's get into it. Since it's been a while, this edition covers more than just the past week. We've pulled together some of the most important updates from the last few months that you'll actually want to know about. Think of it as a catch-up pack. Let's go! 🚀</p><hr><p><strong>Foundation Models: Tool Calling</strong></p><p>The on-device model in the Foundation Models framework can do more than just generate text, you can give it tools that call back into your app when it needs real-time information. Define a <code>Tool</code> conformance and let the model decide when to invoke it:</p><pre><code class="language-swift">struct FlightStatusTool: Tool {
    let name = "FlightStatus"
    let description = "Returns the live status of a flight by number"

    func call(arguments: Arguments) async throws -&gt; ToolOutput {
        let status = await FlightAPI.fetch(flightNumber: arguments.flightNumber)
        return ToolOutput(status)
    }
}

let session = LanguageModelSession(tools: [FlightStatusTool()])
let response = try await session.respond(to: "What's the status of flight UA101?")</code></pre><p>This is the key to building agentic features, apps that don't just respond to text, but actively perform actions on the user's behalf.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@bharathibala21/deep-dive-the-foundation-models-framework-in-ios-26-on-device-ai-that-respects-privacy-d3743b984f35?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Deep Dive: The Foundation Models Framework in iOS 26 — On-Device AI That Respects Privacy</div><div class="kg-bookmark-description">Apple’s commitment to “Privacy by Design” has always been its north star, but with iOS 26 and the new Foundation Models Framework (FMF)…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156-1" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">Mobile Engineering: Build, Lead, Deliver</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/bc1f8416df0cad099e43cda2872716e5864f18a73bda2a7547ea082aca9b5632" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>In the iOS 26.4 update, the Foundation Models framework got improvements to instruction-following and tool-calling abilities. Since the model changes when a person updates their device, you'll want to re-test your prompts with the new model to verify your app's behavior. <a href="https://developer.apple.com/hello/march26/?ref=ioscodereview.com">Apple Developer</a> Worth doing before your next release.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/FoundationModels?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Foundation Models | Apple Developer Documentation</div><div class="kg-bookmark-description">Perform tasks with the on-device model that specializes in language understanding, structured output, and tool calling.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/developer-og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.apple.com/newsroom/2025/09/apples-foundation-models-framework-unlocks-new-intelligent-app-experiences/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Apple’s Foundation Models framework unlocks new intelligent app experiences</div><div class="kg-bookmark-description">Developers around the world are able to bring even more intelligent experiences into their apps by tapping into Apple’s Foundation Models framework.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-5.ico" alt=""><span class="kg-bookmark-author">Apple Newsroom</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/Apple-Foundation-Models-framework-hero-lp.jpg.og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><p><a href="https://developer.apple.com/documentation/FoundationModels?ref=ioscodereview.com">Foundation Models Framework Docs</a> · <a href="https://www.apple.com/newsroom/2025/09/apples-foundation-models-framework-unlocks-new-intelligent-app-experiences/?ref=ioscodereview.com">Apple's Foundation Models in Practice</a></p><hr><p><strong>Swift 6.2: Default Actor Isolation</strong></p><p>If you've been drowning in <code>@MainActor</code> annotations ever since enabling Swift 6's strict concurrency checking, Swift 6.2 has a direct answer. Default Actor Isolation is a new Swift compiler setting that alters the default behavior of concurrency isolation, instead of assuming no isolation, it now assumes your code should run on <code>@MainActor</code> unless you say otherwise.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.avanderlee.com/concurrency/default-actor-isolation-in-swift-6-2/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Default Actor Isolation in Swift 6.2</div><div class="kg-bookmark-description">Use Default Actor Isolation in Swift 6.2 to run code on the @MainActor by default and smoothen your migration.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-2.png" alt=""><span class="kg-bookmark-author">SwiftLee</span><span class="kg-bookmark-publisher">Antoine van der Lee</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/imagegenerator-1.php" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>Enable it in your <code>Package.swift</code>:</p><pre><code class="language-swift">swiftSettings: [
    .defaultIsolation(MainActor.self)
]</code></pre><p>When you need to introduce actual concurrency, opt in with the new <code>@concurrent</code> attribute. <a href="https://www.swift.org/blog/swift-6.2-released/?ref=ioscodereview.com">Swift</a> This gives you a clean mental model: single-threaded by default, concurrent by explicit choice.</p><p>In Xcode 26, newly created projects have this option enabled and set to <code>MainActor</code> by default. <a href="https://fatbobman.com/en/posts/default-actor-isolation/?ref=ioscodereview.com">Fatbobman's Swift Weekly</a> For existing projects, the migration tooling can help you update incrementally, don't just flip the flag globally, as it can silently change the behavior of <code>nonisolated async</code> functions.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.donnywals.com/should-you-opt-in-to-swift-6-2s-main-actor-isolation/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Should you opt-in to Swift 6.2’s Main Actor isolation? – Donny Wals</div><div class="kg-bookmark-description">Swift 6.2 comes with some interesting Concurrency improvements. One of the most notable changes is that there’s now a compiler flag that will, by default, isolate all your (implicitly nonisolated)…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/cropped-site-icon-270x270.png" alt=""><span class="kg-bookmark-author">Donny Wals</span><span class="kg-bookmark-publisher">donnywals</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/should-you-opt-in-to-swift-6-2s-main-actor-isolation.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Swift 6.2: Observations: Transactional State Updates</strong></p><p>Swift 6.2 enables streaming transactional state changes of observable types using the new <code>Observations</code> async sequence type. Updates include all synchronous changes to observable properties, and the transaction ends at the next <code>await</code> that suspends, avoiding redundant UI updates, improving performance, and ensuring your code reacts to a consistent snapshot of the value. <a href="https://www.swift.org/blog/swift-6.2-released/?ref=ioscodereview.com">Swift</a></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/swift-6.2-released/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift 6.2 Released</div><div class="kg-bookmark-description">We’re excited to announce Swift 6.2, a release aimed at making every Swift developer more productive, regardless of where or how you write code. From improved tooling and libraries to enhancements in concurrency and performance, Swift 6.2 delivers a broad set of features designed for real-world development at every layer of the software stack.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-180x180-1.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-touch-icon-180x180-1.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>A subtle but impactful improvement if you've ever had views flickering from multiple rapid state changes.</p><hr><p><strong>Swift 6.2: Exit Testing in Swift Testing</strong></p><p>Swift Testing keeps getting better. Exit testing in Swift 6.2 lets you verify that code terminates under specific conditions, such as a failed precondition. <a href="https://www.swift.org/blog/swift-6.2-released/?ref=ioscodereview.com">Swift</a> Particularly useful for testing defensive guards that should trigger a fatal error:</p><pre><code class="language-swift">@Test func verifyPrecondition() async {
    await #expect(exitsWith: .failure) {
        guard someCondition else { preconditionFailure("Should not reach here") }
    }
}</code></pre><hr><p><strong>Swift in the Browser with WebAssembly</strong></p><p>One of the standout talks from the Pre-FOSDEM Swift event this year: Simon Leeb demonstrated how to run Swift applications natively in the browser with WebAssembly, using ElementaryUI. <a href="https://www.swift.org/blog/whats-new-in-swift-february-2026/?ref=ioscodereview.com">Swift</a> The full <a href="https://www.youtube.com/watch?v=jAgydnnjj0Y&list=PLeb93j_rsErO182fdoJ4m1p_suKAOcBnM&ref=ioscodereview.com">YouTube playlist</a> from the pre-conference event is worth a browse, talks cover embedded Swift, server-side Swift, Android, and more.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/jAgydnnjj0Y?list=PLeb93j_rsErO182fdoJ4m1p_suKAOcBnM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></figure><hr><p><strong>Swift System Metrics 1.0</strong></p><p>The 1.0 release of Swift System Metrics makes it easy to collect process-level metrics like CPU utilization time and memory usage, running on both Linux and macOS with a common API across platforms. <a href="https://www.swift.org/blog/swift-system-metrics-1.0-released/?ref=ioscodereview.com" rel="noreferrer">Swift</a> Handy for any server-side Swift work or for profiling long-running background processes.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/swift-system-metrics-1.0-released/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Announcing Swift System Metrics 1.0: Process-Level Monitoring</div><div class="kg-bookmark-description">We are excited to announce the 1.0 release of Swift System Metrics, a Swift package that collects process-level system metrics like CPU utilization time and memory usage. Swift System Metrics runs on both Linux and macOS, providing a common API across platforms.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-180x180.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/apple-touch-icon-180x180.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>SDK Requirement Deadline</strong></p><p>Mark your calendar. Starting April 28, 2026, apps and games uploaded to App Store Connect must be built with the iOS 26 &amp; iPadOS 26 SDK or later. <a href="https://developer.apple.com/news/?id=ueeok6yw&ref=ioscodereview.com" rel="noreferrer">Apple Developer</a> If you haven't migrated your project to Xcode 26 yet, now is the time.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/news/?id=ueeok6yw&ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Upcoming SDK minimum requirements - Latest News - Apple Developer</div><div class="kg-bookmark-description">Starting April 28, 2026, apps and games uploaded to App&nbsp;Store&nbsp;Connect need to meet the following minimum requirements:
iOS and iPadOS apps must be built with the iOS&nbsp;26&nbsp;&amp; iPadOS&nbsp;26&nbsp;SDK or&nbsp;later
tvOS apps must be built with the tvOS&nbsp;26&nbsp;SDK or&nbsp;later
visionOS apps must be built with the visionOS&nbsp;26&nbsp;SDK or&nbsp;later
watchOS apps must be built with the watchOS&nbsp;26&nbsp;SDK or&nbsp;later
Learn more about submitting</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-logo-1.svg" alt=""><span class="kg-bookmark-author">Apple Developer</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/ios-ipados-og.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p><strong>Design System &amp; Liquid Glass</strong></p><p>If you're building or scaling a design system, John Sundell has a timely piece on the topic over at Swift by Sundell. A design system will probably never be "finished", it needs to continuously evolve to adapt to new designs and system changes from Apple, like the introduction of Liquid Glass in iOS 26. <a href="https://www.swiftbysundell.com/?ref=ioscodereview.com">Swift by Sundell</a> Worth reading if your component library is starting to groan under the weight of custom UI work.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftbysundell.com/articles/building-a-design-system-at-genius-scan/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Building a design system at Genius Scan | Swift by Sundell</div><div class="kg-bookmark-description">An example of how to approach the task of building a design system for an app, by focusing on creating an initial set of reusable components that can be tweaked using the SwiftUI environment.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon.png" alt=""><span class="kg-bookmark-author">Swift by Sundell</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/social.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><hr><p>✌️ That's it for now! Stay curious, ship thoughtfully, and test your prompts with every OS update.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #74 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 74th issue of iOS Code Review! Today&#39;s issue is another collaboration with J’aime Ohm @omt_conf and Kate Roberts @SaltForMySquid. Welcome back, J&#39;aime and Kate. Enjoy! 👇

Runway: Build the perfect release train 
Release trains are not a silver bullet, but ]]></description>
        <link>https://ioscodereview.com/issues/74/</link>
        <guid isPermaLink="false">673b53c32c9f360001db4a43</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 04 Dec 2024 03:30:50 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 74th issue of iOS Code Review! Today's issue is another collaboration with <a href="https://jaimeohm.com/?ref=ioscodereview.com" rel="noreferrer">J’aime Ohm @omt_conf</a> and <a href="https://bsky.app/profile/salt-for-my-squid.bsky.social?ref=ioscodereview.com" rel="noreferrer">Kate Roberts @SaltForMySquid</a>. Welcome back, J'aime and Kate. Enjoy! 👇</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Runway: Build the&nbsp;perfect release train&nbsp;</strong></b><br>Release trains are not a silver bullet, but they can help you ship new versions of your app more predictably, reduce risk, get feedback from users faster, and improve collaboration and planning within your team.<br><a href="https://www.runway.team/blog/how-to-build-the-perfect-mobile-release-train?utm_source=newsletter&utm_medium=code-review&utm_campaign=oct-sponsors" rel="noreferrer">Here’s how to build the perfect mobile release train</a></div></div><h2 id="xcode-and-chatgpt-support">Xcode and ChatGPT Support</h2><p><br>Hot news right now is the announcement of a <a href="https://help.openai.com/en/articles/10119604-work-with-apps-on-macos?ref=ioscodereview.com" rel="noreferrer">direct integration between ChatGPT and Xcode</a> (requires ChatGPT subscription).</p><p>This means less cut and paste. You can assume it will understand the file context of your question, you can highlight incorrect lines when asking it to make corrections, and you can&nbsp; ask it to summarize a file.&nbsp;</p><p>To use it, toggle on "Enable Works with Apps" in ChatGPT settings and then select this icon on the ChatGPT bar:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/12/chatgpt-screenshot.png" class="kg-image" alt="Popover showing a list of applications that can be enabled, including Xcode, TextEdit, Terminal" loading="lazy" width="1600" height="900" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/12/chatgpt-screenshot.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/12/chatgpt-screenshot.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/12/chatgpt-screenshot.png 1600w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">image source: OpenAI.com</span></figcaption></figure><p>And yes – this does give ChatGPT much deeper access into your code (all open windows) – and you should consider the personal and legal aspects of that. Although 'temporary chat' modes are available, it is nonetheless something that your employer might have an opinion on.&nbsp;</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@hiandic/dc21998f3653?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Xcode + ChatGPT: Official Support is Available Now</div><div class="kg-bookmark-description">Free read for non-members: https://medium.com/@hiandic/dc21998f3653?source=friends_link&amp;sk=e4dfbadcc5281bd474ecd546b221877e</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156" alt=""><span class="kg-bookmark-author">Simpra Tech</span><span class="kg-bookmark-publisher">Halil İbrahim Andiç</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/1-ee5nPxlN_bqmA0eW36_dCw.jpeg" alt="" onerror="this.style.display = 'none'"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://youtube.com/playlist?list=PLvHc56e5L-7xgZsgvF2yL7P13lmTwNcoh&ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">ChatGPT + XCode</div><div class="kg-bookmark-description">Video’s delen met vrienden, familie en de rest van de wereld</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon_144x144.png" alt=""><span class="kg-bookmark-author">YouTube</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/hqdefault.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-testing-parameters">Swift Testing: Parameters</h2><p>If you want to run a single test for a range of different parameters, inject them into the test as an argument with <code>@Test(arguments:)</code>. You can inject an array, several arrays, or even zipped arrays - for when the test parameters come in pairs.&nbsp;For example:</p><pre><code class="language-swift">@Test(arguments: zip([18, 30, 50, 70], [77.0, 73, 65, 61]))
&nbsp;&nbsp;func verifyNormalHeartRate(age: Int, bpm: Double) {
&nbsp;&nbsp;&nbsp;&nbsp;let hr = HeartRate(bpm: bpm)
&nbsp;&nbsp;&nbsp;&nbsp;let context = HeartRateContext(age: age, activity: .regular, heartRate: hr)
&nbsp;&nbsp;&nbsp; #expect(context.zone == .normal)
}</code></pre><p>If there is a failure, then the Test Navigator will highlight exactly which parameter values are responsible.&nbsp;</p><figure class="kg-card kg-image-card"><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeBGro6kHBOFvToytHRVfltPq3I6GI9oxweZk4Vta41opb1TS7_ka2i1vPc9n3w-VNfT3wTB9SCYsc8Q-i-S4e-0YXKffqw4vYr7BFHNefXZTjwUJ51tNe3bcAC1YWlshIztHLYOQ?key=YzJjf2cjJhdNONF9WcYF0OA5" class="kg-image" alt="Screenshot of Test Navigator displaying which parameter values passed and which failed" loading="lazy" width="572" height="218"></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/11/12/introducing-swift-testing-parameterized-tests/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introducing Swift Testing. Parameterized Tests.</div><div class="kg-bookmark-description">I decided to finalize the topic of the Swift Testing framework with its unique feature called parameterized tests. In a few cases, you need to verify your functions with different inputs, and parameterized tests easily solve this by providing you with a nice overview.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-2.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/testing-1.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-testing-traits-tags">Swift Testing: Traits &amp; Tags</h2><p>Trait annotation are used to conditionally skip tests based on a feature flag:</p><pre><code class="language-swift">// Conditionally skip tests based on a feature flag
@Test(
&nbsp;&nbsp;&nbsp;&nbsp;.enabled(if: FeatureFlag.addition),
&nbsp;&nbsp;&nbsp;&nbsp;.enabled(if: FeatureFlag.anotherFlag)
)</code></pre><p>Using tags (that you define yourself) lets you run tests by tag and visualize if all the tests in the tag pass:</p><pre><code class="language-swift">// Group tests with a custom tag
@Test(.tags(.crucial, .checkout))

extension Tag {
&nbsp;&nbsp;&nbsp;&nbsp;@Tag static var crucial: Self</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/11/05/introducing-swift-testing-traits/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introducing Swift Testing. Traits.</div><div class="kg-bookmark-description">The most powerful feature of the Swift Testing framework is the trait system. Traits allow us to annotate a test or test suite to customize its behavior. This week, we will learn how to use built-in trait types to modify tests.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-3.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/testing-2.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-testing-suites">Swift Testing: Suites</h2><p>Or why not group your tests using the Suite macro applied to your test class: </p><pre><code class="language-swift">// Name your Suite 
@Suite("Serial model tests") 

// Timeout your Suite
@Suite(.timeLimit(.minutes(1)))

// Serialize your Suite
@Suite(.serialized)</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/10/29/introducing-swift-testing-lifecycle/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introducing Swift Testing. Lifecycle.</div><div class="kg-bookmark-description">Any function marked with the @Test macro can be a test in the world of the Swift Testing framework. But how do you handle the lifecycle of the tests? How do you define test suites and provide setup and teardown functionality? This week, we will learn how to handle the test lifecycle in Swift Testing framework.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-4.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/testing-3.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-testing-require-macro">Swift Testing: Require Macro</h2><p>Let's increase the clarity of your tests by choosing <code>#require</code> to differentiate test pre-requisites from the feature actually being tested. </p><pre><code class="language-swift">try #require(person != nil, "Person should exist")</code></pre><p>For more examples using #require vs #expect, see <a href="https://www.avanderlee.com/swift-testing/require-macro/?ref=ioscodereview.com" rel="noreferrer">SwiftLee</a> and <a href="https://www.donnywals.com/testing-requirements-with-require-in-swift-testing/?ref=ioscodereview.com" rel="noreferrer">Danny Walls</a>.</p><h2 id="improve-your-search-ios-12">Improve Your Search (iOS 12+)</h2><p>Let's leverage powerful and privacy-focused AI/ML tools that are shipped by Apple – like the Natural Language framework – to offer your users smarter search results.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.artemnovichkov.com/blog/working-with-natural-language-framework?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Working with Natural Language framework</div><div class="kg-bookmark-description">Learn how to use the Natural Language framework to analyze text in real time.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/icon.jpg" alt=""><span class="kg-bookmark-author">Artem Novichkov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/cover.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>You can now use the comment section on the website to share your thoughts. Thank you to <a href="https://www.runway.team/blog/how-to-build-the-perfect-mobile-release-train?utm_source=newsletter&utm_medium=code-review&utm_campaign=oct-sponsors" rel="noreferrer"><strong>Runway</strong></a> for sponsoring this issue and thank you to J'aime and Kate for joining us today!<br></p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #73 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 73rd issue of iOS Code Review! I&#39;m waving to you from my vacation in Japan. Today&#39;s issue is a collaboration with J’aime Ohm and Kate Roberts. Welcome back, J&#39;aime in San Francisco. Hello, Kate in London. Enjoy! 👇

KeyboardKit ]]></description>
        <link>https://ioscodereview.com/issues/73/</link>
        <guid isPermaLink="false">6509612352a4ea0001fd6edd</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 20 Nov 2024 03:14:23 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 73rd issue of iOS Code Review! I'm waving to you from my vacation in Japan. Today's issue is a collaboration with J’aime Ohm and Kate Roberts. Welcome back, <a href="https://x.com/jaimeohm?ref=ioscodereview.com" rel="noreferrer">J'aime in San Francisco</a>. Hello, <a href="https://www.linkedin.com/in/kate-roberts-6846075?ref=ioscodereview.com" rel="noreferrer">Kate in London</a>. Enjoy! 👇</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">KeyboardKit Pro</strong></b> lets you create custom iOS keyboards with Swift &amp; SwiftUI, with support for 70 locales and a rich set of features. Skip months of development and deliver a professional custom keyboard that your users will love. <br>Sign up today to secure the current license price before the 9.0 increase. You can save an additional 50% on your first payment with the discount code <code spellcheck="false" style="white-space: pre-wrap;">KK-BF24-LXX8YV8</code>: <a href="https://keyboardkit.com/pro?ref=ioscodereview.com"><b><strong style="white-space: pre-wrap;">https://keyboardkit.com/pro</strong></b></a></div></div><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">&lt;&lt; Your announcement here &gt;&gt;<br>Your sponsorship makes this newsletter possible! As 2024 wraps up, please consider us in your budget for 2025. <a href="https://ioscodereview.com/sponsor/" rel="noreferrer">More info here</a> or simply request a slot by sending an email to <a href="mailto:ioscodereview@hybridcattt.com?subject=Sponsoring%20iOS%20Code%20Review" rel="noreferrer">ioscodereview@hybridcattt.com</a>. </div></div><h2 id="xcode-16-try-swift-testing">Xcode 16: Try Swift Testing</h2><p>We encourage you to write your next new test using Swift Testing instead of XCTest. Swift Testing improves your test suite's readability and makes it easier to run certain kinds of tests. </p><p>Let's swap out XCTest for Swift Testing:</p><pre><code class="language-swift">// import XCTest becomes 
import Testing

// class ExampleTests: XCTestCase becomes 
struct ExampleTests
class ExampleTests // if you want deinit

// override func setup() becomes
init()

// override func teardown() becomes
deinit()

// XCTAssert calls become one of these
#expect(...) 
#expect(customVariable &gt; 10)
#expect(throws: ) { ... } 
#expect(throws: CustomError.self) { ... } 
#expect { ... } throws { ... }

// XCTFail becomes
Issue.record("Custom failure message")

// Prefix your test functions with the Test macro
@Test func ...
@Test("Custom display name") func ...</code></pre><p>We like that multiple <code>XCTAssert</code> formats are collapsed into the new <code>expect</code> macro, due to some cleverness under the hood. For more examples, check out Majid's article on the basics of Swift Testing. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/10/22/introducing-swift-testing-basics/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introducing Swift Testing. Basics.</div><div class="kg-bookmark-description">Swift Testing is a new framework with expressive and intuitive APIs that improve your testing experience. It is powered by macros that allow you to organize and assert your tests. This week, we will learn about the basics of the Swift Testing framework and how we can use it side-by-side with XCTest.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/favicon-1.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/testing.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="secrets-to-success-with-mainactor">Secrets to Success With @MainActor</h2><p>Swift 6's (included in Xcode 16) stricter concurrency checks inspire us to discuss  our do's and don'ts. The MainActor attribute is a hot topic because it has consistently caused confusion since Swift 5.5; here are some secrets to success with this attribute.</p><p>DO: add the MainActor attribute to all your observable classes </p><pre><code class="language-swift">@MainActor @Observable
class ...</code></pre><p>DO NOT: use actors for your observable objects</p><pre><code class="language-swift">// DONT DO THIS
@Observable
actor ...

// NOT THIS EITHER
@CustomGlobalActor @Observable
class ...</code></pre><p>If you kickoff a background task, make sure you return to the MainActor if it needs to be there for completion. </p><pre><code class="language-swift">Task { @MainActor in
  // Do stuff
}
</code></pre><p>For an example using ObservableObject (we use the newer Observation framework's @Observable in the above code snippets) or for more ways to return from a background task, check out the following article by twostraws.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.hackingwithswift.com/quick-start/concurrency/how-to-use-mainactor-to-run-code-on-the-main-queue?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to use @MainActor to run code on the main queue - a free Swift Concurrency by Example tutorial</div><div class="kg-bookmark-description">Learn Swift coding for iOS with these free tutorials</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon.png" alt=""><span class="kg-bookmark-author">Hacking with Swift</span><span class="kg-bookmark-publisher">Paul Hudson twostraws</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/logo-large.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="more-secrets-to-success-with-mainactor">More Secrets to Success With @MainActor</h2><p>We will all run into this. One day, Swift 6 will give you a confusing error that you have a "call to... main actor... in a synchronous context". Prove us wrong and avoid this error entirely with the following DONT.</p><p>DO NOT: call your main actor method <strong>synchronously</strong> from code that <em>could</em> execute on a thread that is not the main thread. In Swift 5.x, this will cause the <code>@MainActor</code> annotation to be silently ignored and the method will not be called on the main actor: </p><pre><code class="language-swift">DispatchQueue.global().async {
  exampleMethod()
}
...
@MainActor
func exampleMethod() {...} </code></pre><p>To reflect on MainActor as a global actor, learn to create your own global actors, and review more ways to use the MainActor attribute, you can go deeper with Antoine van der Lee here:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.avanderlee.com/swift/mainactor-dispatch-main-thread/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">MainActor usage in Swift explained to dispatch to the main thread</div><div class="kg-bookmark-description">MainActor in Swift replaces DispatchQueue.main and ensures tasks are performing on the main thread in a performant manner.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/apple-touch-icon-1.png" alt=""><span class="kg-bookmark-author">SwiftLee</span><span class="kg-bookmark-publisher">Antoine van der Lee</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/imagegenerator.php" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="customising-writing-with-intelligence">Customising Writing With Intelligence </h2><p>When it comes to Apple Intelligence - available in iOS 18 - the most currently visible feature is Writing Tools. Writing Tools uses AI to offer to rewrite your text.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/11/IMG_0157.jpeg" class="kg-image" alt="" loading="lazy" width="1179" height="1394" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/11/IMG_0157.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/11/IMG_0157.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/11/IMG_0157.jpeg 1179w" sizes="(min-width: 720px) 720px"></figure><p>We use the new <a href="https://developer.apple.com/documentation/swiftui/view/writingtoolsbehavior(_:)?ref=ioscodereview.com" rel="noreferrer"><code>writingToolsBehavior</code></a> modifier to customize Writing Tools on any Text, TextEditor, or TextField.</p><pre><code class="language-swift">.writingToolsBehavior(.autocomplete) // default
.writingToolsBehavior(.complete) // turn it on
.writingToolsBehavior(.disabled) // turn it off
.writingToolsBehavior(.limited) // simplified</code></pre><p>This article provides further customization of WritingTools through UIKit and discusses the features, animations, and ubiquity of Writing Tools.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.createwithswift.com/exploring-apple-intelligence-writing-tools/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Exploring Apple Intelligence: Writing Tools</div><div class="kg-bookmark-description">Understand Writing Tools, powered by Apple Intelligence.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/icon/CwS-Logo.svg" alt=""><span class="kg-bookmark-author">Create with Swift</span><span class="kg-bookmark-publisher">Antonella Giugliano</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/thumbnail/createwithswift.com-exploring-apple-intelligence-writing-tools.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-evolution-proposals">Swift Evolution Proposals </h2><p>[Accepted] We are delighted to see that <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0439-trailing-comma-lists.md?ref=ioscodereview.com"><u>trailing comma in comma-separated lists</u></a> has been accepted. This will make for smaller diffs and&nbsp;make it easier to append, remove, and re-order comma-separated lists.&nbsp;</p><p>[In Review] Does the <a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0453-vector.md?ref=ioscodereview.com"><u>lack of a native Vector type</u></a> concern you? Or do Arrays adequately serve your needs?</p><h2 id="upcoming-events">Upcoming Events</h2><ul><li><a href="https://github.com/mRs-/Black-Friday-Deals/blob/811898ee7bcc477b3140e049bf39dcb845b5f865/README.md?ref=ioscodereview.com"><u>Black Friday Deals</u></a>: Like last year, Marius Landwehr's Github offers a master list of Black Friday deals. We recommend bookmarking this (it will grow) for returning to on Black Friday.&nbsp;</li><li><a href="https://adventofcode.com/?ref=ioscodereview.com"><u>Advent of Code</u></a> returns with free daily Swift challenges starting December 1</li><li>Mikaela Caron and Paul Hudson are back with <a href="https://podcasts.apple.com/gb/podcast/swift-over-coffee/id1435076502?i=1000676386646&ref=ioscodereview.com"><u>Swift Over Coffee</u></a>, discussing everything from Apple Intelligence to Swift 6. Next episode’s poll: what are your Swift papercuts? </li></ul><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>You can now use the comment section on the website to share your thoughts. Thank you to <a href="https://keyboardkit.com/pro?ref=ioscodereview.com" rel="noreferrer">KeyboardKit Pro</a> for sponsoring this issue and thank you to J'aime and Kate for joining us today ❤️<br></p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #72 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 72nd issue of iOS Code Review! Today I’m joined by J’aime, who is your author for today. Enjoy! 👇

Whew! What a whirlwind summer and fall, eh? WWDC Announcements, Swift 6, AI advancements, plus in-person conferences and events are making a comeback. We have ]]></description>
        <link>https://ioscodereview.com/issues/72/</link>
        <guid isPermaLink="false">672a02bdff269b0001c83cb9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 06 Nov 2024 03:00:17 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 72nd issue of iOS Code Review! Today I’m joined by J’aime, who is your author for today. Enjoy! 👇</p><p>Whew! What a whirlwind summer and fall, eh? WWDC Announcements, Swift 6, AI advancements, plus in-person conferences and events are making a comeback. We have a few selections from these developments here for your reading pleasure.</p><p>Thank you, Marina, for welcoming me to join you for this week's iOS Code Review. It's been heaps of fun putting this issue together with you.</p><p>– <a href="https://x.com/jaimeohm?ref=ioscodereview.com" rel="noreferrer">J'aime Ohm</a>, enjoyer of newsletters and director of <a href="https://omt-conf.com/?ref=ioscodereview.com"><u>One More Thing</u></a></p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Runway: Build the&nbsp;perfect release train&nbsp;</strong></b><br>Release trains are not a silver bullet, but they can help you ship new versions of your app more predictably, reduce risk, get feedback from users faster, and improve collaboration and planning within your team.<br><a href="https://www.runway.team/blog/how-to-build-the-perfect-mobile-release-train?utm_source=newsletter&utm_medium=code-review&utm_campaign=oct-sponsors" rel="noreferrer">Here’s how to build the perfect mobile release train</a></div></div><h2 id="swift-6-typed-throws">Swift 6: Typed Throws</h2><p>Throwing functions can now throw typed errors. You can add a type <code>throws(ErrorName)</code> in the function declaration. Or, add a type in a <code>do(ErrorName)...catch</code> declaration.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed-throws.md?ref=ioscodereview.com#proposed-solution"><div class="kg-bookmark-content"><div class="kg-bookmark-title">swift-evolution/proposals/0413-typed-throws.md at main · swiftlang/swift-evolution</div><div class="kg-bookmark-description">This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">swiftlang</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/4bdb40ceb434ff31149155a040c8df42a2242ff5bcee4e3acb174d4eb352382f/swiftlang/swift-evolution" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="how-do-we-make-illegal-states-unrepresentable">How do we make illegal states unrepresentable? </h2><p>DONT: have a model that supports an `illegal state`, like modeling no payment method (nil, nil) as shown below.</p><pre><code class="language-Swift">struct PaymentMethod: Codable {
  let creditCard: CreditCard?
  let giftCard: GiftCard?
}</code></pre><p>DO: have a model that supports only `legal states`, like modeling only one or more payment methods, as shown below. </p><pre><code class="language-Swift">enum PaymentMethod {
  case creditCard(CreditCard)
  case giftCard(GiftCard)
}</code></pre><p>This article has various examples of the clever use of Swift types to make such states impossible.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftology.io/articles/making-illegal-states-unrepresentable/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Making illegal states unrepresentable | Swiftology</div><div class="kg-bookmark-description">In state modeling, perfection is achieved not when there is nothing more to add, but when there is nothing left to take away.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftology.io/images/favicon.png" alt=""><span class="kg-bookmark-author">Swiftology</span><span class="kg-bookmark-publisher">Alex Ozun</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftology.io/tydd5.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="entry-in-swiftui">@Entry in SwiftUI </h2><p>This macro condenses the declaration of <code>Environment</code>, <code>Transaction</code>, <code>Container</code>, and <code>Focused</code> values. </p><pre><code class="language-Swift">extension EnvironmentValues {
    @Entry var myCustomValue: String = "Default value"
}</code></pre><p>Read about the before-and-after in the article below, and check out <a href="https://developer.apple.com/documentation/swiftui/entry()?ref=ioscodereview.com" rel="noreferrer">official documentation</a></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftwithvincent.com/blog/new-in-swiftui-the-macro-entry?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">New in SwiftUI: the macro @Entry — Swift with Vincent</div><div class="kg-bookmark-description">You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://images.squarespace-cdn.com/content/v1/63139bb1e1a1a078e071f30c/bd40c4d4-dc8b-48b7-a0cc-2209de7d1ab6/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Vincent</span><span class="kg-bookmark-publisher">Vincent Pradeilles</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://static1.squarespace.com/static/63139bb1e1a1a078e071f30c/63139c36429a5c059fca0020/6727a0c0822a1a6ce1507e24/1730650721196/maxresdefault.jpg?format=1500w" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="videos-from-swiftcraft-uk-2024">Videos from SwiftCraft UK 2024</h2><p>Videos from SwiftCraft UK are up on YouTube. Thank you again to SwiftCraft UK for sponsoring this newsletter in March and April of 2024.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/videoseries?list=PLugrLwuQvERqB4Kj8GOPwCnUMOLxJ0Ny9" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></figure><h2 id="copilot-for-xcode-is-here">Copilot for Xcode is here</h2><p>The popular AI coding tool <code>Copilot</code> has now been released by Github as an offical extension for Xcode. To try it you need to disable Xcode 16's predictive code completion.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://dimillian.medium.com/github-copilot-for-xcode-62931a645173?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub Copilot for Xcode</div><div class="kg-bookmark-description">Microsoft released an Xcode extension in a surprising turn of event</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://miro.medium.com/v2/resize:fill:304:304/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">Thomas Ricouard</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/da:true/resize:fit:1200/0*tbkW5QGlntDV_6Gb" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="a-couple-of-how-tos">A couple of how-tos </h2><p><strong>Improving User Privacy in Multitasking by Blurring Views </strong><br>When the environment variable <code>scenePhase</code> changes to <code>inactive</code> or <code>background</code>, sensitive views can be animated with blur by using modifier <code>.blur(blurRadius:</code> to 20.&nbsp;</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.createwithswift.com/implement-blurring-when-multitasking-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Implement blurring when multitasking in SwiftUI</div><div class="kg-bookmark-description">Learn how to implement automatic screen blurring in SwiftUI apps to enhance user privacy when the app enters multitasking mode.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.createwithswift.com/content/images/size/w256h256/format/png/2024/01/CwS-Logo.svg" alt=""><span class="kg-bookmark-author">Create with Swift</span><span class="kg-bookmark-publisher">Giovanni Monaco</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.createwithswift.com/content/images/size/w1200/2024/10/createwithswift.com-implement-blurring-when.multitasking-in-swiftui.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><p><strong>When you really really <em>really</em> need your app reviewed quickly</strong><br>Go to <em>contact us</em> at the bottom of developer.apple.com and keep selecting an option with <em>App Review</em> in it until you reach <em>Expedited App Review Request</em>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.polpiella.dev/expedited-app-reviews/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to expedite an app review on the App Store</div><div class="kg-bookmark-description">A guide on how you can use expedited app reviews in exceptional circumstances to get your app reviewed faster than normal on the App Store.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.polpiella.dev/assets/favicon.png" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.polpiella.dev/api/thumbnail?title=How%20to%20expedite%20an%20app%20review%20on%20the%20App%20Store" alt="" onerror="this.style.display = 'none'"></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>You can now use the comment section on the website to share your thoughts.<br>Thank you to <a href="https://www.runway.team/?ref=ioscodereview.com" rel="noreferrer">Runway</a> for sponsoring this issue and thank you to J’aime for joining us today ❤️</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #71 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 71st issue of iOS Code Review 👋

I&#39;m really excited about a recent addition to the website - the comment section! Now all registered users (ie all email subscribers) can leave public comments on the issues. If you don&#39;t see the comment ]]></description>
        <link>https://ioscodereview.com/issues/71/</link>
        <guid isPermaLink="false">66f1ce2fea61bf00019e4026</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 24 Sep 2024 03:08:19 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 71st issue of iOS Code Review 👋</p><p>I'm really excited about a recent addition to the website - the comment section! Now all registered users (ie all email subscribers) can leave public comments on the issues. If you don't see the comment section - click "Sign in" to get the magic link to your email. <br>Looking forward to engaging in the open dialog or just reading your thoughts. And of course your emails are always a warmth to my heart :)</p><p>Now let's dive in!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Is it possible to make releases boring?</strong></b><br>Squarespace’s Unfold team did. Learn what these non-eventful releases are like and how they came about, dig into how eventful they used to be, and hear why having uneventful releases is a superpower.<br><a href="https://engineering.squarespace.com/blog/2024/unfolds-modern-mobile-release-process-and-the-subtle-art-of-making-them-boring?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Read on Squarespace's blog</strong></b></a></div></div><h2 id="ask-wwdc-ai">Ask WWDC AI </h2><p>Someone (<a href="https://x.com/matthew_spear?ref=ioscodereview.com" rel="noreferrer">Matt Spear</a>) built an AI Q&amp;A layer on top of WWDC database. You can ask it any prompt and it will spit out a detailed answer together with links to relevant WWDC sessions. Here's my example about RoomPlan. This is genius. </p><figure class="kg-card kg-image-card"><img src="https://media.tenor.com/uBvOeO5Hf78AAAAC/really-wow.gif" class="kg-image" alt="" loading="lazy" width="262" height="200"></figure><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/09/swift-developer-wwdc-ask-ai.png" class="kg-image" alt="" loading="lazy" width="1328" height="1654" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/09/swift-developer-wwdc-ask-ai.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/09/swift-developer-wwdc-ask-ai.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/09/swift-developer-wwdc-ask-ai.png 1328w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://askwwdc.com/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Ask WWDC</div><div class="kg-bookmark-description">Catching up on WWDC? Ask a question and we’ll give you a concise summary and recommend the most relevant sessions to watch!</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://askwwdc.com/favicon.ico" alt=""><span class="kg-bookmark-author">Ask WWDC</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://askwwdc.com/card.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="scroll-view-margins-in-swiftui">Scroll view margins in SwiftUI</h2><p>TIL about <a href="https://developer.apple.com/documentation/swiftui/view/contentmargins(_:for:)?ref=ioscodereview.com" rel="noreferrer">contentMargins available in SwiftUI from iOS 17</a> - the margin is added to the entire content of the scroll view. No need for extra spacers anymore 😬 There are various visual examples in the article 👇 </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://serialcoder.dev/text-tutorials/swiftui/insetting-scrollable-views-content-with-contentmargins-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Insetting Scrollable Views’ Content With contentMargins In SwiftUI – SerialCoder.dev</div><div class="kg-bookmark-description">Adding margin to content of scrollable views in SwiftUI is just a matter of a single view modifier. Read here all you need to know about it.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://serialcoder.dev/wp-content/uploads/2020/10/cropped-serialcoder_icon-1-270x270.png" alt=""><span class="kg-bookmark-author">SerialCoder.dev</span><span class="kg-bookmark-publisher">Gabriel Theodoropoulos</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://serialcoder.dev/wp-content/uploads/2024/09/contentmargins_featured.jpg" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="swift-regex-examples">Swift Regex examples </h2><p>If you’ve ever struggled with regular expressions in Swift, this GitHub repo offers a clean and practical set of examples using Swift’s native&nbsp;<code>Regex</code>&nbsp;type: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/DandyLyons/NativeRegexExamples?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - DandyLyons/NativeRegexExamples: A crowd sourced repository for examples of Swift’s native Regex type.</div><div class="kg-bookmark-description">A crowd sourced repository for examples of Swift’s native Regex type. - DandyLyons/NativeRegexExamples</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">DandyLyons</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/fc115c4cdcd34179410dbe5d1536be451ff201b27c1b3bd9b0f2094c120edd47/DandyLyons/NativeRegexExamples" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>Aaaaand an online playground for playing around with Swift Regex:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftregex.com/?s=H4sIAAAAAAAAA6VRwU6DQBD9lcnGxDYiLIu1SW%2FY5bBRoSnbk%2BsBgXIQWAJLIql8jX%2Fil7m0CVo8ePAlk5nJ5r15s3NAFVqh2XrrUcbfqXfH%2BFyI5momRHKwDdJbZ8VNP0cGkmj1hDJdFOjZQMrWCvfMp3AEdbkHI5gfcsZ3nAU%2BTOA%2BBjufi%2FL6nxDlyf2giR0L2xbBhAzdJupqmeewr2UBaVHlskvr0%2FALgrFJnCnXGblh21RprMCd2h64BsZ4CBNjUR4%2FDX4r8DS5bGCTKtjK%2BBXCqIxVG9XdXwqLUYHKNtMStM1kq3SXNd8eHMckyzPq7c%2Fhwdte1gmsZVFEepeqyjt4UImpnz4%2FFkvT0avrA77o0%2BmkyJD7Lxfrlj8NAgAA&ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift Regex: Learn, build and test Swift Regex</div><div class="kg-bookmark-description">Regular Expression Tester with highlighting for Swift Regex. Quickly test and debug your regex and Regex Builder.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftregex.com/apple-touch-icon.png" alt=""><span class="kg-bookmark-author">Swift Regex: Learn, build and test Swift Regex and Regex Builder.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftregex.com/images/ogp_image.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><h2 id="enormous-swiftui-app-architecture-guide">Enormous SwiftUI app architecture guide  </h2><p>Building large-scale apps in SwiftUI can be tricky, and a modular architecture is our friend. I dug up this super extensive article – sometimes that's just what you need 😀<br>When it comes to app architecture, taste plays a big role, but nonetheless one can find useful bits. I loved the idea of skipping the MVVM pattern and letting views talk directly to models, at least sometimes, not over-complicating areas of the app that <em>can</em> be kept simple.  </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://azamsharp.com/2023/02/28/building-large-scale-apps-swiftui.html?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Building Large Scale Apps Swiftui</div><div class="kg-bookmark-description">Building Large-Scale Apps with SwiftUI: A Guide to Modular Architecture</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">AzamSharp</span><span class="kg-bookmark-publisher">Mohammad Azam</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://azamsharp.com/images/view-debugging.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://www.runway.team/?ref=ioscodereview.com" rel="noreferrer">Runway</a> for sponsoring this issue ❤️</p><p>Your comments in the comment section or direct replies by email are always welcome!<br></p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #70 ]]></title>
        <description><![CDATA[ Hi there! Hope you missed the newsletter at least a little bit 😁 A short break turned into a long summer break, but we&#39;re back!

I started a new full time job as an engineering manager in a small startup in climate space called Lun. I&#39;m still ]]></description>
        <link>https://ioscodereview.com/issues/70/</link>
        <guid isPermaLink="false">66d4ce8b3504fd0001b81372</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 02 Sep 2024 03:30:09 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there! Hope you missed the newsletter at least a little bit 😁 A short break turned into a long summer break, but we're back! </p><p>I started a new full time job as an engineering manager in a small startup in climate space called <a href="https://lun.energy/?ref=ioscodereview.com" rel="noreferrer">Lun</a>. I'm still coding, alas not as much as before. The project is heavy on iOS specific tech in AR space which I feel is rare in startups nowadays, and I'm loving it! Loved it so much that after consulting with them for a few months, I accepted their offer to join full-time. </p><p>It's wasn't an easy decision to let go of the "indie dream" (at least for now), but I'm actually very happy with it - turns out I thrive around other people 😀</p><p>Now that I've adjusted to the 9-5x5 again, I feel energised to bring the newsletter back in. Having said that, I'm looking for a partner to get the project going full steam. If that sparks curiosity, write me 👀</p><p>Now, let me share a few articles that grabbed my interest:</p><h2 id="typesafe-identifiers-my-favourite-way">Typesafe identifiers, my favourite way</h2><p>On my favourite topic of type-safe identifiers in Swift, Jacob wrote up exactly the way I prefer to manage them by defining a struct for each, but making it a one-liner to do so, no macros involved. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://jacobzivandesign.com/technology/people_make_mistakes/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Humans write code, and humans make mistakes. | Jacob Zivan Design</div><div class="kg-bookmark-description">One thing I’ve learned is to **just freaking** let the compiler prevent me from making mistakes. Sometimes that’s hard to do, then I learned about something called a Domain Primitive and I decided to give it a try in Swift.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://jacobzivandesign.com/images/favicon.png" alt=""><span class="kg-bookmark-author">Jacob Zivan Design</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://jacobzivandesign.com/images/social.jpg" alt=""></div></a></figure><h2 id="concurrency-in-detail">Concurrency in detail</h2><p>Two articles that are a perfect for each other. Diving into Swift Concurrency, a guide I didn't know I needed when starting with it a while back. And some things to watch out for to avoid subtle bugs when introducing Swift Concurrency into existing large codebases. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.massicotte.org/step-by-step-network-request?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Concurrency Step-by-Step: A Network Request</div><div class="kg-bookmark-description">When I was first learning to program I had absolutely no idea what I was doing. I was using C, and I remember desperately putting in * and &amp; characters until things compiled. But, this was pre-Mac OS X. Upon running my horrifically incorrect programs, half the time the screen would become corrupted and the mouse would stop moving. I’d then have to reboot the whole machine via a physical switch. This was … frustrating.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">massicotte.org</span><span class="kg-bookmark-publisher">Matt Massicotte</span></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://jaimzuber.com/swift-concurrency/how-to-shoot-yourself-in-the-foot.html?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to shoot yourself in the foot with Swift Concurrency - Too Many Tasks</div><div class="kg-bookmark-description">Adopting async/await and Swift Concurrency in a large codebase can cause subtle bugs to creep in your code. Here are some things to watch out for.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://jaimzuber.com/apple-touch-icon.png" alt=""><span class="kg-bookmark-author">Jaim Zuber</span><span class="kg-bookmark-publisher">Jaim Zuber</span></div></div></a></figure><h2 id="format-styles-in-excruciating-detail">Format styles in excruciating detail</h2><p>Along with closure syntax and if-case-let syntax, format styles warrant their own guiding website of this sort. While I could find logical mnemonics for closures in Objective-C and for if-case let, SwiftUI's format styles still break my brain every time. Bookmarking this!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://goshdarnformatstyle.com/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Format Styles In Excruciating Detail</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://goshdarnformatstyle.com/favicon/apple-touch-icon.png" alt=""><span class="kg-bookmark-author">Gosh Darn Format Style!</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://goshdarnformatstyle.com/cuss.svg" alt=""></div></a></figure><h2 id="beautiful-async-buttons">Beautiful async buttons</h2><p>Spotlighting a library I found myself enjoying oddly much. ButtonKit offers a button component that supports async actions - with beautiful out-of-the-box progress styles and a whole bunch of customisations. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/Dean151/ButtonKit?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - Dean151/ButtonKit: Asynchronous and Throwable button implementation for SwiftUI, with animations and progress tracking</div><div class="kg-bookmark-description">Asynchronous and Throwable button implementation for SwiftUI, with animations and progress tracking - Dean151/ButtonKit</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">Dean151</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/f526482b95eb50835581fd28b9ab78bf7541a78cbe90959e341c11aee8dda8eb/Dean151/ButtonKit" alt=""></div></a></figure><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Setapp</strong></b> offers a collection of 240+ trustworthy, advanced apps under one simple subscription. You will find apps such as <i><em class="italic" style="white-space: pre-wrap;">Ulysses</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Paste</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Asset Catalog Creator Pro</em></i>, <i><em class="italic" style="white-space: pre-wrap;">DevUtils</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Craft</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Structured</em></i>, and many more. <br><a href="https://setapp.sjv.io/ioscodereview?ref=ioscodereview.com" rel="noreferrer">Try Setapp for free</a></div></div><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #69 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 69th issue of iOS Code Review. Let&#39;s dive into this issue&#39;s insights and discoveries together ✨

Step into the future of Apple tech at Pragma Conference 2024, happening October 29-30 in Bologna, Italy! Get ready for a full day of deep-dive workshops ]]></description>
        <link>https://ioscodereview.com/issues/69/</link>
        <guid isPermaLink="false">662eb6ee913ab10001da9c68</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 29 Apr 2024 02:59:36 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 69th issue of iOS Code Review.  Let's dive into this issue's insights and discoveries together ✨</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">Step into the future of Apple tech at <b><strong style="white-space: pre-wrap;">Pragma Conference 2024</strong></b>, happening October 29-30 in Bologna, Italy! Get ready for a full day of deep-dive workshops followed by two days jam-packed with sessions and awesome networking. This is THE event for Apple developers — you won't want to miss it!<br><a href="https://pragmaconference.com/?utm_source=newsletter&utm_medium=email&utm_campaign=ioscodereview1&utm_id=ioscodereview" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Secure your spot!</strong></b></a></div></div><h2 id="goodbye-geometryreader-hello-containerrelativeframe">Goodbye GeometryReader, hello containerRelativeFrame</h2><p>From iOS 17 we can use <code>containerRelativeFrame(_:alignment:)</code> for giving views size calculated from the size of its parent. <code>containerRelativeFrame(_:count:span:spacing:alignment:)</code> is to be used when multiple views will be visible in the container.</p><p>Refer to official documentation for in-depth explanation, or to a video by Flo for a quick overview:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/swiftui/view/containerrelativeframe(_:alignment:)?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">containerRelativeFrame(_:alignment:) | Apple Developer Documentation</div><div class="kg-bookmark-description">Positions this view within an invisible frame with a size relative to the nearest container.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/swiftui/view/containerrelativeframe(_:count:span:spacing:alignment:)?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">containerRelativeFrame(_:count:span:spacing:alignment:) | Apple Developer Documentation</div><div class="kg-bookmark-description">Positions this view within an invisible frame with a size relative to the nearest container.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><figure class="kg-card kg-embed-card"><iframe width="200" height="150" src="https://www.youtube.com/embed/nLo_vVKVNWM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Stop using GeometryReader in SwiftUI"></iframe></figure><h2 id="new-content-margins-modifier">New Content Margins modifier</h2><p>Another handy iOS 17 addition in SwiftUI is a view modifier called <code>contentMargins</code> . It allows to inset the content of some of the system views, without getting additional side effects that come from adjusting the safe area:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/04/23/content-margins-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Content margins in SwiftUI</div><div class="kg-bookmark-description">SwiftUI introduced a set of view modifiers, allowing us to manage the safe area in our views efficiently. In many cases, the safe area is where you want to put your content. Today, we will learn about the new content margin concept that SwiftUI introduced and how it differs from the safe area.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftwithmajid.com/public/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftwithmajid.com/public/margins3.png" alt=""></div></a></figure><h2 id="computed-property-or-a-function">Computed property or a function</h2><p><code>func name() -&gt; String</code> or <code>var name: String</code> , <code>func nearestNeighbour() -&gt; String</code> or <code>var nearestNeighbour: String</code> ? There are conventions in Swift that will help you decide:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.donnywals.com/deciding-between-a-computed-property-and-a-function-in-swift/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Deciding between a computed property and a function in Swift – Donny Wals</div><div class="kg-bookmark-description">In Swift, we can use computed properties to derive a value from other values defined on the same object. Being able to do this is super convenient because it means that we don’t have to manually make…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.donnywals.com/wp-content/uploads/cropped-site-icon-270x270.png" alt=""><span class="kg-bookmark-author">Donny Wals</span><span class="kg-bookmark-publisher">donnywals</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.donnywals.com/wp-content/og_images/deciding-between-a-computed-property-and-a-function-in-swift.png" alt=""></div></a></figure><h2 id="overrated-swift-features">Overrated Swift features</h2><p>In this article you'll read about a few Swift features that seem cool but do more harm than good when overused: implicit initialisers with <code>.init</code>, subscripts, and more:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@SaezChristopher/the-cool-swift-features-that-you-should-not-ab-use-61070b70fad9?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The cool Swift features that you should not (ab)use</div><div class="kg-bookmark-description">As an iOS developer, I used to work on a lot of legacy code, or I tried some Swift features myself. After using them or seeing some of them…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">Christopher Saez 📱</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:536/1*k1m6z_VjnRq7NM2Ke5ZeAg.png" alt=""></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://pragmaconference.com/?utm_source=newsletter&utm_medium=email&utm_campaign=ioscodereview1&utm_id=ioscodereview" rel="noreferrer">Pragma Conference</a> for sponsoring this issue ❤️</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #68 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 68th issue of iOS Code Review! I hope the spring is treating you well ☀️ I&#39;ve been traveling, and also started a new job as an engineering manager. I&#39;ll write more about my reasons behind this step later on when I gather ]]></description>
        <link>https://ioscodereview.com/issues/68/</link>
        <guid isPermaLink="false">661e3fac62a9c30001efe091</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 16 Apr 2024 02:25:01 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 68th issue of iOS Code Review! I hope the spring is treating you well ☀️ I've been traveling, and also started a new job as an engineering manager. I'll write more about my reasons behind this step later on when I gather my thoughts. In the meantime, enjoy today's learnings ❤️</p><h2 id="everything-about-the-aasa-file">Everything about the AASA file</h2><p><em>"The&nbsp;</em><a href="https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html?ref=ioscodereview.com" rel="noreferrer"><em>Apple App Site Association (AASA) file</em></a><em>&nbsp;enables iOS features like Universal Links, Shared Web Credentials, Handoff, and App Clips by establishing a secure and verified link between your iOS app(s) and a web domain.&nbsp;</em></p><p><em>If you've noticed that certain links on the mobile web versions of Instagram or YouTube keep you in the browser, while others redirect you into the app, this behavior is all being driven by the AASA file."</em></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://digitalbunker.dev/apple-app-site-association/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Everything You Need To Know About The Apple App Site Association File</div><div class="kg-bookmark-description">The Apple App Site Association (AASA) file enables iOS features like Universal Links, Shared Web Credentials, Handoff, and App Clips by establishing a secure and verified link between your iOS app(s) and a web domain. If you’ve noticed that certain links on the mobile web versions of Instagram or</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://digitalbunker.dev/favicon.ico" alt=""><span class="kg-bookmark-author">Digital Bunker</span><span class="kg-bookmark-publisher">Aryaman Sharda</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1518835693946-9578ff2c4a4f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDIyfHxyb2Fkd2F5fGVufDB8fHx8MTcxMjk2NTgyN3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt=""></div></a></figure><h2 id="contentunavailableview-ftw">ContentUnavailableView FTW</h2><p>I shared something about this new view back when iOS 17 was just released. Coincidentally, now I'm using it in a project for real for the first time, and a few days later another article came out - with examples of its possible states, and screenshots! At first I wasn't sure that my view was looking the way it should, and I looked for ways to adjust spacing. It's not possible, but I can see that my view looks just the way it is expected to, so I'll leave it be :) </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.createwithswift.com/display-empty-states-with-contentunavailableview-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Display empty states with ContentUnavailableView in SwiftUI</div><div class="kg-bookmark-description">Learn how to use the ContentUnavailableView to represent empty states in a SwiftUI application.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.createwithswift.com/content/images/size/w256h256/format/png/2024/01/CwS-Logo.svg" alt=""><span class="kg-bookmark-author">Create with Swift</span><span class="kg-bookmark-publisher">Pasquale Vittoriosi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.createwithswift.com/content/images/size/w1200/2024/04/display-empty-states-with-contentunavailableview-in-swiftui-001.png" alt=""></div></a></figure><h2 id="overcoming-obstacles">Overcoming obstacles</h2><p>Obvious to more seasoned engineers, these techniques are the way to go when you're stuck:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.supereasyapps.com/5-practical-ways-to-quickly-overcome-a-programming-obstacle/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">5 Practical Ways to Quickly Overcome a Programming Obstacle</div><div class="kg-bookmark-description">Are you stuck on a programming challenge? Does the code not compile? Does the API work differently than you expect? Little problems can add up and get in the way of seeing the big picture. As a software developer, you need to be able to overcome these obstacles. Here are</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.supereasyapps.com/content/images/size/w256h256/2017/11/super_easy_symbol-200px-1.png" alt=""><span class="kg-bookmark-author">Super Easy Apps</span><span class="kg-bookmark-publisher">Paul Solt</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.supereasyapps.com/content/images/size/w1200/2024/04/2024-4-11-5-Practical-Ways-to-Quickly-Overcome-a-Programming-Obstacle-1.png" alt=""></div></a></figure><h2 id="there-is-no-right-or-wrong-in-software-engineering-often">There is no right or wrong in software engineering (often)</h2><p><em>"... when it comes to software engineering, the reality is&nbsp;most things cannot be cleanly divided into "right or wrong" boxes like that.&nbsp;Yes, some things are concrete and indisputable. If an OS-level API states that you should never call it outside of the main thread, then that's what you should follow.<br>But most things are the opposite of that. When we talk about general problems and best practices, it's extremely rare for them to have a clear right or wrong to go. Instead,&nbsp;they depend on what you're trying to achieve, and everyone is trying to achieve something different.There is no right or wrong in these situations, only different approaches. "</em></p><p>I subscribe to this approach, highly recommend reading this article if you're aiming at senior level or above:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftrocks.com/there-is-no-right-or-wrong-in-software-engineering?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">There is no right or wrong in software engineering</div><div class="kg-bookmark-description">Developers love to argue about which tools and languages are better. In this article, we’ll see that things are not that straightforward in practice.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftrocks.com/images/favicon/iconsmall2.png" alt=""><span class="kg-bookmark-author">SwiftRocks</span><span class="kg-bookmark-publisher">Bruno Rocha</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftrocks.com/images/thumbs/thumb.jpg?4" alt=""></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">Are you motivated by the <i><em class="italic" style="white-space: pre-wrap;">craft</em></i> of writing Swift? Want to improve your productivity and the quality of your results? Want to hang out with other awesome developers with the same mindset?<br><br><b><strong style="white-space: pre-wrap;">Swift Craft</strong></b>&nbsp;is a brand new conference for passionate developers working on Apple platforms. Set in a UK seaside town with stunning views across the English Channel, with an incredible line up of some of the community' top speakers, delivering dozens of sessions on the latest Swift features and writing even better code - this is the inaugral event you won't want to miss!<br><br><a href="https://swiftcraft.uk/?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Find out more and check out the full schedule</strong></b></a></div></div><figure class="kg-card kg-image-card"><a href="https://swiftcraft.uk/?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg" class="kg-image" alt="" loading="lazy" width="2000" height="1999" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/swiftcraft_JPG-05-1.jpg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/swiftcraft_JPG-05-1.jpg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2024/03/swiftcraft_JPG-05-1.jpg 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg 2000w" sizes="(min-width: 720px) 720px"></a></figure> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #67 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 67th issue of iOS Code Review! I hope the spring is treating you well ☀️ Let&#39;s learn something new!

Are you motivated by the craft of writing Swift? Want to improve your productivity and the quality of your results? Want to hang out with ]]></description>
        <link>https://ioscodereview.com/issues/67/</link>
        <guid isPermaLink="false">660cf1579f3c31000198de2a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 03 Apr 2024 05:22:37 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 67th issue of iOS Code Review! I hope the spring is treating you well ☀️ Let's learn something new! </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">Are you motivated by the <i><em class="italic" style="white-space: pre-wrap;">craft</em></i> of writing Swift? Want to improve your productivity and the quality of your results? Want to hang out with other awesome developers with the same mindset?<br><br><b><strong style="white-space: pre-wrap;">Swift Craft</strong></b>&nbsp;is a brand new conference for passionate developers working on Apple platforms. Set in a UK seaside town with stunning views across the English Channel, with an incredible line up of some of the community' top speakers, delivering dozens of sessions on the latest Swift features and writing even better code - this is the inaugral event you won't want to miss!<br><br><a href="https://swiftcraft.uk/?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Find out more and check out the full schedule</strong></b></a></div></div><h2 id="handling-family-shared-in-app-subscriptions">Handling family shared in-app subscriptions</h2><p>Apple's sample code for managing in-app purchases has a line of code that is seemingly innocent, but in fact makes the example not support Family Sharing for in-app subscriptions:</p><pre><code class="language-Swift">subscriptionGroupStatus = try? await subscriptions.first?.subscription?.status.first?.state</code></pre><p>Here <code>status</code> is an array and any the elements can be in a subscribed status: <br><em>" ... With Family Sharing, the people who are using the subscription act independently: one may subscribe for a year and then cancel. Then another could subscribe at a later date for only a month. You have to check all of the subscriptions, not just the first one.&nbsp;... "</em></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://furbo.org/2024/03/29/app-store-subscriptions-and-family-sharing/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">App Store Subscriptions and Family Sharing • furbo.org</div><div class="kg-bookmark-description">A toot by my friend Casey brought back some frustrating memories about expired subscriptions that haven’t expired (yes, really). This blog post will hopefully help you avoid having these same recollections. It all begins when a customer contacts you with a screenshot that looks something like this: Your code and the App Store don’t agree […]</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://furbo.org/wp-content/uploads/2023/04/furbo.png" alt=""><span class="kg-bookmark-author">Furbo.org by Craig Hockenberry</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://furbo.org/wp-content/uploads/2024/03/AppStoreViewAlert.png" alt=""></div></a></figure><h2 id="date-decoding-strategies-in-swift-with-examples">Date decoding strategies in Swift, with examples</h2><p>We don't usually use the default <code>.deferredToDate</code> <code>decodingStrategy</code> of the <code>JSONDecoder</code>/<code>JSONEncoder</code>, and here's a nice article walking through the different options and when you want to use them:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://matteomanferdini.com/datedecodingstrategy/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Date decoding strategies in Swift [with Examples]</div><div class="kg-bookmark-description">The JSONDecoder class uses several decoding strategies to decode dates encoded using different formats in JSON data.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://matteomanferdini.com/wp-content/uploads/2023/08/cropped-favicon-270x270.jpg" alt=""><span class="kg-bookmark-author">Matteo Manferdini</span><span class="kg-bookmark-publisher">Matteo Manferdini</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://matteomanferdini.com/wp-content/uploads/2024/03/datedecodingstrategy-facebook.jpeg" alt=""></div></a></figure><h2 id="trigger-value-pattern-in-swiftui">Trigger value pattern in SwiftUI</h2><p><em>" The recent version of the SwiftUI framework introduces a trigger value pattern across its APIs. Trigger value allows us to attach a view modifier that runs its action whenever the trigger value changes. You can find this pattern while using sensory feedback or launching keyframe animation in SwiftUI. This week, we will learn how to build custom view modifiers using trigger value pattern. " </em></p><p>Here's an example of a SwiftUI API using this pattern:</p><pre><code class="language-Swift">struct TriggerValueExample: View {
    let messages: [String]
    
    var body: some View {
        List(messages, id: \.self) { message in
            Text(verbatim: message)
        }
        .sensoryFeedback(.impact, trigger: messages)
    }
}</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2024/04/02/trigger-value-pattern-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Trigger value pattern in SwiftUI</div><div class="kg-bookmark-description">The recent version of the SwiftUI framework introduces a trigger value pattern across its APIs. Trigger value allows us to attach a view modifier that runs its action whenever the trigger value changes. You can find this pattern while using sensory feedback or launching keyframe animation in SwiftUI. This week, we will learn how to build custom view modifiers using trigger value pattern.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftwithmajid.com/public/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftwithmajid.com/public/swiftui.png" alt=""></div></a></figure><h2 id="wwdc23-videos-are-now-on-youtube">WWDC'23 videos are now on YouTube</h2><p>All videos from WWDC'23 are now available on YouTube, nicely grouped into themed playlists 🎉 </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.youtube.com/@AppleDeveloper/playlists?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Apple Developer</div><div class="kg-bookmark-description">Hello and welcome to the official Apple Developer YouTube channel.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.youtube.com/s/desktop/0646520c/img/favicon_144x144.png" alt=""><span class="kg-bookmark-author">YouTube</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://yt3.googleusercontent.com/UwhdIoePC5SaKsqJyRvv3lrRGalezBQYQIk15Wqkn6c45bMkpkRadSRqeQgkyFksOnhzg9e-CQ=s900-c-k-c0x00ffffff-no-rj" alt=""></div></a></figure><h2 id="wwdc24-special-event-application">WWDC'24 Special Event application</h2><p><em>Tonight</em> is the deadline for requesting to participate in the in-person event at this year's WWDC. If that's your type of thing, you can apply here: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/wwdc24/special-event/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">WWDC24 Apple Park Special Event</div><div class="kg-bookmark-description">We’re hosting a special all-day experience at Apple Park on June 10 to kick off WWDC24.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://developer.apple.com/wwdc24/images/og/phase-1-cba/wwdc24-special-event-og.png" alt=""></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p>Thank you to <a href="https://swiftcraft.uk/?ref=ioscodereview.com" rel="noreferrer">Swift Craft conference</a> for sponsoring this issue ❤️</p><figure class="kg-card kg-image-card"><a href="https://swiftcraft.uk/?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg" class="kg-image" alt="" loading="lazy" width="2000" height="1999" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/swiftcraft_JPG-05-1.jpg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/swiftcraft_JPG-05-1.jpg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2024/03/swiftcraft_JPG-05-1.jpg 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg 2000w" sizes="(min-width: 720px) 720px"></a></figure> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #66 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 66th issue of iOS Code Review! Today we&#39;ll dive into what&#39;s new in Swift 5.10 which was just released as part of Xcode 15.3, the Observation framework, and an accessibility topic. Enjoy 🙌

Are you motivated by the craft of ]]></description>
        <link>https://ioscodereview.com/issues/66/</link>
        <guid isPermaLink="false">65f82965f044dc0001a82770</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 18 Mar 2024 06:34:21 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 66th issue of iOS Code Review! Today we'll dive into what's new in Swift 5.10 which was just released as part of Xcode 15.3, the Observation framework, and an accessibility topic. Enjoy 🙌</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">Are you motivated by the <i><em class="italic" style="white-space: pre-wrap;">craft</em></i> of writing Swift? Want to improve your productivity and the quality of your results? Want to hang out with other awesome developers with the same mindset?<br><br><b><strong style="white-space: pre-wrap;">Swift Craft</strong></b>&nbsp;is a brand new conference for passionate developers working on Apple platforms. Set in a UK seaside town with stunning views across the English Channel, with an incredible line up of some of the community' top speakers, delivering dozens of sessions on the latest Swift features and writing even better code - this is the inaugral event you won't want to miss!<br><br><a href="https://swiftcraft.uk/?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Find out more and check out the full schedule</strong></b></a></div></div><h2 id="whats-new-in-swift-510">What's new in Swift 5.10</h2><p>Swift 5.10 achieves an even further level of <em>concurrency checking</em> - preventing the app from <em>data races</em> and <em>undefined behaviour</em>. </p><p>"<br>An increasingly important source of <strong>undefined behavior</strong> is concurrent code that inadvertently <strong>accesses memory from one thread</strong> at the same time that <strong>another thread is writing to the same memory</strong>. This kind of unsafety is called a&nbsp;<strong>data race</strong>, and data races make concurrent programs exceptionally difficult to write correctly. Swift solves this problem through&nbsp;<strong>data isolation</strong>&nbsp;provided by actors and tasks, which guarantees <strong>mutually exclusive access</strong> to shared mutable state. Data isolation enforcement has been under active development since 2020 when the&nbsp;<a href="https://forums.swift.org/t/swift-concurrency-roadmap/41611?ref=ioscodereview.com">Swift concurrency roadmap</a>&nbsp;was posted. <br>...<br>In Swift 5.10, full data isolation is enforced at compile time in all areas of the language when the complete concurrency checking option is enabled.<br>...<br>The Swift 6.0 compiler will offer a new, opt-in Swift 6 language mode that will enforce full data isolation by default, and we will embark upon the transition to eliminate data races across all software written in Swift.<br>"</p><p>Read about the new checks and errors in Swift 5.10, which complete years of iterative development and prepares us for Swift 6:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/swift-5.10-released/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift 5.10 Released</div><div class="kg-bookmark-description">Swift was designed to be safe by default, preventing entire categories of programming mistakes at compile time. Sources of undefined behavior in C-based languages, such as using variables before they’re initialized or a use-after-free, are defined away in Swift.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swift.org/apple-touch-icon-180x180.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swift.org/apple-touch-icon-180x180.png" alt=""></div></a></figure><h2 id="have-you-tried-observation-framework">Have you tried Observation framework?</h2><p>I've stumbled on three articles that are perfectly timed to my interest in understanding the <code>Observation</code> framework. <code>Observation</code> framework is iOS 17+ only, but iOS 18 is just around the corner, so it's a good time to learn more about <code>Observation</code>. Here they are!</p><p>The official, step by step guide on migrating your models, with sample code:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Migrating from the Observable Object protocol to the Observable macro | Apple Developer Documentation</div><div class="kg-bookmark-description">Update your existing app to leverage the benefits of Observation in Swift.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><p>If the official documentation is not your style, Donny Wals has written an article on comparing the old and the new approach:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.donnywals.com/comparing-observable-to-observableobjects/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Comparing @Observable to ObservableObjects – Donny Wals</div><div class="kg-bookmark-description">Find out how you can leverage the new @Observable macro in your apps. You’ll lean how it compares to ObservableObject and whether it makes sense to switch</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.donnywals.com/wp-content/uploads/cropped-site-icon-270x270.png" alt=""><span class="kg-bookmark-author">Donny Wals</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.donnywals.com/wp-content/og_images/comparing-observable-to-observableobjects.png" alt=""></div></a></figure><h2 id="unit-testing-observable-models">Unit testing Observable models </h2><p>When your view models are @Observable and use the new Observation framework, the Combine-based unit tests won't work anymore. Jacob shows how he uses <code>withObservationTracking</code> in his code to test the new models:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://jacobbartlett.substack.com/p/unit-test-the-observation-framework?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Unit Test the Observation Framework</div><div class="kg-bookmark-description">Make your iOS 17 view models rock-solid</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4f0abf-a3f6-476c-b60a-0adae74b83e3%2Fapple-touch-icon-180x180.png" alt=""><span class="kg-bookmark-author">Jacob’s Tech Tavern</span><span class="kg-bookmark-publisher">Jacob Bartlett</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://substackcdn.com/image/fetch/w_1200,h_600,c_fill,f_jpg,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d8d84a3-4e26-4346-9b1f-7ee190f5e4da_700x467.jpeg" alt=""></div></a></figure><h2 id="accessibility-representation-modifier">Accessibility Representation modifier</h2><p>Here's the key parts from the article, couldn't say it better than the author himself:</p><p>"<br>In app development, it's not uncommon for two distinct views to have the same appearance and functionalities, despite being implemented differently. ... For example, an&nbsp;<code>Image</code>&nbsp;view with an&nbsp;<code>onTapGesture</code>&nbsp;modifier may appear and function like a&nbsp;<code>Button</code>&nbsp;component, but the&nbsp;VoiceOver&nbsp;experience can be completely different. <br>...<br>The&nbsp;<a href="https://developer.apple.com/documentation/swiftui/view/accessibilityrepresentation(representation:)?ref=createwithswift.com"><code>accessibilityRepresentation(representation:)</code></a>&nbsp;modifier in SwiftUI is designed to transform how an app's elements are perceived by assistive technologies, such as VoiceOver. ... This modifier allows developers to provide alternative representations of their components that are more accessible for users using assistive technologies, ensuring that the app's functionality is accessible to everyone.<br>"</p><p>Check out code examples in the full article:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.createwithswift.com/making-a-view-accessible-using-the-accessibility-representation-modifier/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Making a view accessible using the Accessibility Representation modifier</div><div class="kg-bookmark-description">Learn how to ensure the accessibility of your custom views by replacing their accessible representation.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.createwithswift.com/content/images/size/w256h256/format/png/2024/01/CwS-Logo.svg" alt=""><span class="kg-bookmark-author">Create with Swift</span><span class="kg-bookmark-publisher">Pasquale Vittoriosi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.createwithswift.com/content/images/size/w1200/2024/03/createwithswift.com-making-a-view-accessible-using-the-accessibility-representation-modifier.png" alt=""></div></a></figure><p>✌️<br></p><p>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email.<br><br>Thank you to <a href="https://swiftcraft.uk/?ref=ioscodereview.com" rel="noreferrer">Swift Craft conference</a> for sponsoring this issue ❤️</p><figure class="kg-card kg-image-card"><a href="https://swiftcraft.uk/?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg" class="kg-image" alt="" loading="lazy" width="2000" height="1999" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/swiftcraft_JPG-05-1.jpg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/swiftcraft_JPG-05-1.jpg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2024/03/swiftcraft_JPG-05-1.jpg 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/swiftcraft_JPG-05-1.jpg 2001w" sizes="(min-width: 720px) 720px"></a></figure> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #65 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 65th issue of iOS Code Review! Today I have six learnings to share, let&#39;s dive in 👇


Type-driven design

In issue #62 I shared an article from Swiftology talking about a pattern called TypeState, where types are used to restrict code from moving to ]]></description>
        <link>https://ioscodereview.com/issues/65/</link>
        <guid isPermaLink="false">65e601a2d32aef0001dac170</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 05 Mar 2024 03:24:22 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 65th issue of iOS Code Review! Today I have six learnings to share, let's dive in 👇</p><h2 id="type-driven-design">Type-driven design</h2><p>In <a href="https://ioscodereview.com/issues/62/" rel="noreferrer">issue #62</a> I shared an article from Swiftology talking about a pattern called TypeState, where types are used to restrict code from moving to incorrect states. Now there's more in that article series.:</p><p><em>Type-safe validation</em>: instead of checking if an email is valid and deciding whether to proceed with logic, what if a value of <code>Email</code> struct can only be constructed if the email matches the requirements?</p><p><em>Type-safe access control</em>: similarly, instead of a Bool controlling access to a certain feature, what if a feature flag was a struct that can only be constructed if allowed? This "proof" value can then be passed along to views that are only allowed to exist if the feature is enabled. </p><p>These are really cool approaches. Get inspired to look at the type system in a new light!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftology.io/articles/tydd-part-2/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Type-safe validation | Swiftology</div><div class="kg-bookmark-description">Validation is a very common task in software engineering. We need to validate stuff all the time: user inputs, data formats, array bounds, external configurations, etc. In this article I will show you how to perform validation in a type-safe way, eliminating a whole class of bugs.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftology.io/images/favicon.png" alt=""><span class="kg-bookmark-author">Swiftology</span><span class="kg-bookmark-publisher">Alex Ozun</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftology.io/validation.png" alt=""></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftology.io/articles/tydd-part-3/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Witness pattern — type-safe access control | Swiftology</div><div class="kg-bookmark-description">A common challenge in software design is ensuring that access to a certain functionality is restricted under specific preconditions. In this article, I will show you how to design bulletproof type-safe access control using the **Witness Pattern**.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftology.io/images/favicon.png" alt=""><span class="kg-bookmark-author">Swiftology</span><span class="kg-bookmark-publisher">Alex Ozun</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftology.io/witness.png" alt=""></div></a></figure><h2 id="verifying-associated-domains">Verifying associated domains</h2><p>I remember the pain to verify that associated domains are configured correctly in the app and on the website. Now there's a built in tool:</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/polpielladev/status/1757811996647739397?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-polpielladev-20240214_170013-1757811996647739397-1.png" class="kg-image" alt="" loading="lazy" width="1729" height="1729" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/pikaso.me-polpielladev-20240214_170013-1757811996647739397-1.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/pikaso.me-polpielladev-20240214_170013-1757811996647739397-1.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2024/03/pikaso.me-polpielladev-20240214_170013-1757811996647739397-1.png 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-polpielladev-20240214_170013-1757811996647739397-1.png 1729w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="combining-sf-symbols">Combining SF symbols</h2><p>Check out the video in this tweet - I had no idea it's possible to combine two SF symbols into one by drag and dropping them together. And if you're not yet using the <a href="https://developer.apple.com/sf-symbols/?ref=ioscodereview.com" rel="noreferrer">SF Symbols app, here it is</a></p><figure class="kg-card kg-image-card"><a href="https://twitter.com/daafdaan/status/1760577227014418919?s=12&ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-Daafdaan-20240222-swift-developer-newsletter-1.png" class="kg-image" alt="" loading="lazy" width="1080" height="1500" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/pikaso.me-Daafdaan-20240222-swift-developer-newsletter-1.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/pikaso.me-Daafdaan-20240222-swift-developer-newsletter-1.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-Daafdaan-20240222-swift-developer-newsletter-1.png 1080w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="using-inout">Using inout </h2><p>Back to code! <code>inout</code> can make Swift code even more reusable - take a look at this example of updating local variables. When I first used inout in a complex code, it wasn't obvious that <code>didSet</code> on the variable was called at the end of the function that takes it as <code>inout</code>. Something to keep in mind!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://danielsaidi.com/blog/2024/02/18/the-power-of-inout-parameters?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The power of inout parameters</div><div class="kg-bookmark-description">In Swift, inout parameters can reduce code duplication and the amount of code needed to perform certain tasks. Let’s take a look.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://danielsaidi.com/assets/icon/icon-180.png" alt=""><span class="kg-bookmark-author">Daniel Saidi</span><span class="kg-bookmark-publisher">danielsaidi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://danielsaidi.com/assets/blog/2024/240218/title.jpg" alt=""></div></a></figure><h2 id="accessing-icloud-files">Accessing iCloud files</h2><p>To access files from the file picker correctly, we need to do two things:</p><ul><li>call  <a href="https://developer.apple.com/documentation/foundation/nsurl/1417051-startaccessingsecurityscopedreso?ref=ioscodereview.com" rel="noreferrer"><code>`startAccessingSecurityScopedResource()</code></a> and <a href="https://developer.apple.com/documentation/foundation/nsurl/1413736-stopaccessingsecurityscopedresou?ref=ioscodereview.com"><code>stopAccessingSecurityScopedResource()</code></a>&nbsp;</li><li>wrap reading the files in <a href="https://developer.apple.com/documentation/foundation/nsfilecoordinator/1411533-coordinate?ref=ioscodereview.com"><code>NSFileCoordinator.coordinate(with:queue:byAccessor:)</code></a> so the access doesn't conflict with another app writing to the file at the same time.</li></ul><p>Below is a code example for how to correctly do this:</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/mortengregersen/status/1763177356405936473?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-mortengregersen-swift-developer-newsletter.png" class="kg-image" alt="" loading="lazy" width="1080" height="826" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/pikaso.me-mortengregersen-swift-developer-newsletter.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/pikaso.me-mortengregersen-swift-developer-newsletter.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-mortengregersen-swift-developer-newsletter.png 1080w" sizes="(min-width: 720px) 720px"></a></figure><figure class="kg-card kg-image-card"><a href="https://twitter.com/ronyfadel/status/1763188649191969101?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-ronyfadel-swift-developer-newsletter.png" class="kg-image" alt="" loading="lazy" width="1080" height="1121" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/03/pikaso.me-ronyfadel-swift-developer-newsletter.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/03/pikaso.me-ronyfadel-swift-developer-newsletter.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/03/pikaso.me-ronyfadel-swift-developer-newsletter.png 1080w" sizes="(min-width: 720px) 720px"></a></figure><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Setapp</strong></b> offers a collection of 240+ trustworthy, advanced apps under one simple subscription. You will find apps such as <i><em class="italic" style="white-space: pre-wrap;">Ulysses</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Paste</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Asset Catalog Creator Pro</em></i>, <i><em class="italic" style="white-space: pre-wrap;">DevUtils</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Craft</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Structured</em></i>, and many more. <br><a href="https://setapp.sjv.io/ioscodereview?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Try Setapp for free</strong></b></a></div></div><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #64 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 2^6th issue of iOS Code Review! Only 9 days left until spring. Perfect time to learn something new!


Don&#39;t write recursive functions in Swift

Apparently recursive functions can cause a stack overflow. TIL! If your data is dynamic and the recursion can ]]></description>
        <link>https://ioscodereview.com/issues/64/</link>
        <guid isPermaLink="false">65d4ff7bf75b1f00015f2421</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 20 Feb 2024 12:21:17 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 2^6th issue of iOS Code Review! Only 9 days left until spring. Perfect time to learn something new!</p><h2 id="dont-write-recursive-functions-in-swift">Don't write recursive functions in Swift</h2><p>Apparently recursive functions can cause a stack overflow. TIL! If your data is dynamic and the recursion can get unpredictably deep, better avoid it altogether and use a while loop instead. </p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Correct me if I wrong. Should we never use recursive functions in Swift? Whenever I have deep tree It crashes with stack overflow exception. <a href="https://t.co/leSMw6j8SD?ref=ioscodereview.com">pic.twitter.com/leSMw6j8SD</a></p>— Majid Jabrayilov (@mecid) <a href="https://twitter.com/mecid/status/1757708571670695996?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 14, 2024</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></figure><h2 id="avoid-using-default-enum-case">Avoid using default enum case</h2><p>I'm a big advocate for strong typing and compiler checks helping avoid bugs and speed up development. And the most basic example of that is switching over an enum. If we spell out all cases explicitly, when a new case is added, the compiler notifies us of all points that need changing.<br>If you have a colleague that still needs convincing, this is a nice short article on the matter :) </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://oconnelltoby.medium.com/swift-enums-and-the-danger-of-the-default-case-625a0830f57a?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Swift enums and the danger of the default case</div><div class="kg-bookmark-description">How not to lay traps for future developers</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">Toby O’Connell</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:722/1*r9oGH-Kg1lj9ugy00Hlsbw.png" alt=""></div></a></figure><h2 id="previewing-ciimage-in-the-debugger">Previewing CIImage in the debugger</h2><p>Did you know you can quick-look items in the variables pane of the debugger? That includes not only plain data such as strings and arrays, but also UIImage variables. Even more, a CIImage variable preview includes additional information such as transforms. Check out that little 👁️ icon in the debugger panel! Mike here shares a demo video in the tweet 👇</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I'm not a huge fan of breakpoints. I still use print statements all over the place when debugging 😅 But sometimes, a breakpoint can save you a ton of time, as it may provide additional information.<br><br>When working with AVFoundation, if you tap Quick Look on a CIImage variable, you… <a href="https://t.co/aGbsQJ7Mjf?ref=ioscodereview.com">pic.twitter.com/aGbsQJ7Mjf</a></p>— Mike Mikina (@mikemikina) <a href="https://twitter.com/mikemikina/status/1752975233823220014?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 1, 2024</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></figure><h2 id="on-separating-ui-and-logic">On separating UI and logic</h2><p>Can't decide on the view / logic boundary? Ask yourself: “What if this feature should also work as a Command Line Tool?”. I've been personally using this approach for architecting a clear separation and API surface for the domain logic. I love seeing a full-feature article describing this way of thinking:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftindepth.com/articles/what-if-your-feature-was-a-command-line-tool/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">What if your feature was a Command Line Tool?</div><div class="kg-bookmark-description">When working with UI, it can sometimes be ambiguous where to place business logic. By imagining our features as a Command Line Tool, this can become quite clear.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swiftindepth.com/favicon.ico" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.swiftindepth.com/assets/articles/what-if-your-feature-was-a-command-line-tool/opengraph.png" alt=""></div></a></figure><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Setapp</strong></b> offers a collection of 240+ trustworthy, advanced apps under one simple subscription. You will find apps such as <i><em class="italic" style="white-space: pre-wrap;">Spark Mail,</em></i> <i><em class="italic" style="white-space: pre-wrap;">Ulysses</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Paste</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Asset Catalog Creator Pro</em></i>, <i><em class="italic" style="white-space: pre-wrap;">DevUtils</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Craft</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Structured</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Awesome Habits</em></i>, and many more. <a href="https://setapp.sjv.io/ioscodereview?ref=ioscodereview.com" rel="noreferrer">Try Setapp for free</a></div></div><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p>PS. This time I'm trying a new way of embedding tweets. Send me your feedback on how that shows up in your email client.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #63 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 63rd issue of iOS Code Review!

You might have noticed that this email comes from a new email address. This change was necessary for the new sending requirements for Gmail and Yahoo inboxes - so emails come from the trusted domain ghost.io.

That&#39; ]]></description>
        <link>https://ioscodereview.com/issues/63/</link>
        <guid isPermaLink="false">65bb86b95e7dfd00012c8e63</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Mon, 05 Feb 2024 03:17:38 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 63rd issue of iOS Code Review!</p><p>You might have noticed that this email comes from a new email address. This change was necessary for the new sending requirements for Gmail and Yahoo inboxes - so emails come from the trusted domain <em>ghost.io</em>. </p><p>That's also why I had to remove the  symbol from the email subject and sender - else it lands in gmail spam.</p><p>To make sure the newsletter doesn't land in spam in the future, mark it as starred, add the new email to contacts, or move it to your primary inbox if you use gmail. </p><p>Now let's dive in!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">You're a mobile engineer. Stop tinkering with Ruby scripts.<br><br><b><strong style="white-space: pre-wrap;">Runway</strong></b>&nbsp;handles all the busy work of releases so that you can do the real work so that you can focus on building features instead of Fastlane scripts.<br><br><a href="https://runway.team/?utm_source=codereview&utm_medium=newsletter&utm_campaign=febsponsors" rel="noreferrer">Try Runway for free</a></div></div><h2 id="serialising-dictionary-writes-correctly">Serialising dictionary writes correctly</h2><p>Did you know that <code>dict[id] = data</code> actually does two operations: first, reading the current state using the property getter of <code>dict</code> and then setting the new modified dictionary with the setter. </p><p>So when we want to make sure that access to the dictionary is performed serially from the same queue, it's not enough to add <code>DispatchQueue.sync</code> to <code>willSet</code> of the property.  <br>In his article Toomas shares his story of uncovering an intermittent issue caused by an incorrect implementation and finding fix. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://augmentedcode.io/2024/01/29/avoiding-subtle-mistake-when-guarding-mutable-state-with-dispatchqueue/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Avoiding subtle mistake when guarding mutable state with DispatchQueue</div><div class="kg-bookmark-description">Last week, I spent quite a bit of time on investigating an issue which sometimes happened, sometimes did not. There was quite a bit of code involved running on multiple threads, so tracking it down…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://augmentedcodesite.files.wordpress.com/2017/11/site-icon.png?w=192" alt=""><span class="kg-bookmark-author">Augmented Code</span><span class="kg-bookmark-publisher">Toomas Vahter</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://augmentedcodesite.files.wordpress.com/2017/11/site-icon.png?w=200" alt=""></div></a></figure><h2 id="document-directory-path-changes">Document directory path changes</h2><p>When persisting local file urls (to CoreData or elsewhere) we need to use relative urls and append the documents directory base path in runtime. Full urls to files in the documents directory might become invalid in the future. TIL!</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/lascorbe/status/1752816255310909500?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/02/luis-2024-02-01-13.37.15.png" class="kg-image" alt="" loading="lazy" width="1330" height="570" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/02/luis-2024-02-01-13.37.15.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/02/luis-2024-02-01-13.37.15.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/02/luis-2024-02-01-13.37.15.png 1330w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="what-if-we-stopped-nitpicking">What if we stopped nitpicking?</h2><p>Some time ago I was asked one of those questions in an interview, what would I do differently today compared to the past. I had the answer - as a lead developer, I'd allow for more creative freedom in the codebase, and move away from too rigid coding guidelines that govern every little detail of writing code. There are things that matter, and things that don't. Rules that make sense for public APIs and foundation code don't necessarily make sense for feature code that changes often.</p><p>When I stumbled on this 3-year old article about the impact of nitpicking on the team culture, I could relate to it so much. Nowadays my reviews are balanced, and I learned to let go of my perfectionism. But I wish I read an article like this many years ago and didn't have to learn it by experience :D </p><p>These days my go-to approach is: automate as much as can be automated, and let the humans do what computers can't - think of architecture, edge cases, UX, and so on.</p><p>I loved this quote: <em>"Developers like to imagine that they are composed of nothing but cold, hard logic; but actually, we are humans with unavoidable feelings and emotions." </em><br>Dan shares his story of learning the impact of too much nitpicking the hard way. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.danlew.net/2021/02/23/stop-nitpicking-in-code-reviews/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Stop Nitpicking in Code Reviews</div><div class="kg-bookmark-description">One of the best changes I’ve made at work recently is to stop nitpicking in code
reviews. Nitpicking isn’t about code that is wrong but suboptimal. It’s pointing out a
variable name that could use a more appropriate word, a conditional that could
be formatted more cleanly,</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.danlew.net/favicon.ico" alt=""><span class="kg-bookmark-author">Dan Lew Codes</span><span class="kg-bookmark-publisher">Dan Lew</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.danlew.net/content/images/size/w600/2022/12/00079-1207338963-highly-detailed-2.jpg" alt=""></div></a></figure><h2 id="thinking-of-2024">Thinking of 2024</h2><p>I'm considering to change the newsletter to be weekly, with 3 sections each time, instead of 5 sections every two weeks. It would take a bit more effort, but that way I can share more learnings with all of you! Would you like to receive the newsletter weekly? Please let me know, for example by simply replying "yes" to the email.  </p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://runway.team/?utm_source=codereview&utm_medium=newsletter&utm_campaign=febsponsors" rel="noreferrer">Runway</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #62 ]]></title>
        <description><![CDATA[ Hi there, welcome to the first issue of 2024!
I hope you had wonderful holidays, and are ready for the new year. Let&#39;s remember to have a balance between work, fun, and rest 🧑‍💻🌳🛋️

We passed 3000 subscribers over the holidays, a warm welcome to everyone who just joined ]]></description>
        <link>https://ioscodereview.com/issues/62/</link>
        <guid isPermaLink="false">65a903b8fa0e190001975df9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 18 Jan 2024 04:04:53 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the first issue of 2024! <br>I hope you had wonderful holidays, and are ready for the new year. Let's remember to have a balance between work, fun, and rest 🧑‍💻🌳🛋️</p><p>We passed 3000 subscribers over the holidays, a warm welcome to everyone who just joined 👋 I'm grateful to y'all loyal subscribers for being along with the ride 🎉</p><p>Let's dive into some learnings 🤿</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Setapp</strong></b> offers a collection of 240+ trustworthy, advanced apps under one simple subscription. You will find apps such as <i><em class="italic" style="white-space: pre-wrap;">Ulysses</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Paste</em></i>, <i><em class="italic" style="white-space: pre-wrap;">DevUtils</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Asset Catalog Creator Pro</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Craft</em></i>, <i><em class="italic" style="white-space: pre-wrap;">Structured</em></i>, and many more. <br><a href="https://setapp.sjv.io/ioscodereview?ref=ioscodereview.com" rel="noreferrer">Try Setapp for free</a></div></div><h2 id="naming-unit-tests">Naming unit tests</h2><p>When a test fails, we want&nbsp;to understand what broke. When a name is descriptive, we can get the gist of what broke without reading the test code. It's especially useful when a test failure happens on CI. Jon describes a good formula for naming the tests:</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/01/TestNaming-big.png.webp" class="kg-image" alt="" loading="lazy" width="1420" height="714" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2024/01/TestNaming-big.png.webp 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2024/01/TestNaming-big.png.webp 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2024/01/TestNaming-big.png.webp 1420w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://qualitycoding.org/unit-test-naming/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Unit Test Naming: The 3 Most Important Parts | Quality Coding</div><div class="kg-bookmark-description">Have you run tests, gotten a failure, and had to dig through test code to understand it? Use this unit test naming convention for faster feedback.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://qualitycoding.org/wp-content/uploads/2020/06/favicon.png" alt=""><span class="kg-bookmark-author">Quality Coding</span><span class="kg-bookmark-publisher">Jon Reid</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://qualitycoding.org/wp-content/uploads/2020/04/social-test-naming-scaled.jpg" alt=""></div></a></figure><h2 id="uiimage-memory-footprint">[UI]Image memory footprint</h2><p>Memory usage ≠ file size. <br><em>"Memory use is related to the dimensions of the image, not the file size."</em> - <a href="https://developer.apple.com/videos/play/wwdc2018/416/?ref=ioscodereview.com" rel="noreferrer noopener">Session 416, WWDC 2018</a></p><p>To reduce our app's memory footprint and reduce chances of the app being killed in the background, we can:</p><ul><li>make sure there are no memory leaks (in UIKit, views deallocate). Use Debug Navigator (spraypaint icon in Xcode) and Leaks and Allocation instruments.</li><li>downsample images to view size before display (an image larger than its frame uses memory unnecessarily). See the article for how to do it. </li><li>when an image cache library is used, remember to set the memory cache limit.</li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftsenpai.com/development/reduce-uiimage-memory-footprint/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Reducing Memory Footprint When Using UIImage - Swift Senpai</div><div class="kg-bookmark-description">Learn how to use image downsampling to drastically reduce an app memory footprint when dealing with high definition UIImage.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://i0.wp.com/swiftsenpai.com/wp-content/uploads/2019/09/cropped-swift-senpai-logo.png?fit=192%2C192&amp;ssl=1" alt=""><span class="kg-bookmark-author">Swift Senpai</span><span class="kg-bookmark-publisher">Lee Kah Seng</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftsenpai.com/wp-content/uploads/2020/11/UIImage-Memory-Footprint-Feature-Image.png" alt=""></div></a></figure><h2 id="typestate-pattern-next-level-type-safety">Typestate pattern: next-level type safety</h2><p>The concept of&nbsp;typestates&nbsp;describes the encoding of information about the current state of an object into the type of that object. I'm a big proponent of using the type system to apply domain constraints, so the compiler checks that logic for us. </p><p>In this article you can learn how generics and noncopyable types available from Swift 5.9 help take type safety to another level:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftology.io/articles/typestate/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Typestate - the new Design Pattern in Swift 5.9 | Swiftology</div><div class="kg-bookmark-description">In this article I will introduce you to Typestate pattern, popularised by Rust language, now available in Swift 5.9. You will see how the combination of generic constraints and Swift’s new memory ownership model allows you to write bulletproof code.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftology.io/images/favicon.png" alt=""><span class="kg-bookmark-author">Swiftology</span><span class="kg-bookmark-publisher">Alex Ozun</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftology.io/typestate.png" alt=""></div></a></figure><h2 id="what-game-are-you-playing-in-life">What game are you playing in life?</h2><p>We are in the beginning of a new year, perfect time to reflect. <br>Imagine your career as a game. What game is that? What are the objectives? What level are you at, and what quest do you need to complete to advance to the next level? I'm curious to hear in replies what that is for you ☺️</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@davidbbn/complete-and-total-gamification-life-as-a-game-577d2680cbc2?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Complete And Total Gamification: Life as a Game</div><div class="kg-bookmark-description">This article is inspired by one of my favourite scenes from Guy Ritchie’s The Gentlemen and a great book called Games People Play, by Eric…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">David Babayan</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1088/0*RwGt2NImF7Z0UwOH.jpg" alt=""></div></a></figure><h2 id="new-video-alert">New video alert</h2><p>I visited The Mayank Show to share my insights on becoming a lead developer. We talked about boosting your career, moving abroad, system design, mentoring, running a newsletter, conferences, and what's different between 2011 and now 😁 </p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/3yBUoJD2ZxM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="How to become a Senior iOS Developer in 2024 ft. Marina @hybridcattt"></iframe></figure><p><br>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p><em>* this issue contains an affiliate link to </em><a href="https://setapp.sjv.io/ioscodereview?ref=ioscodereview.com" rel="noreferrer"><em>Setapp</em></a></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #61 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 61st issue of iOS Code Review! Here&#39;s to another round of curated learnings ☺️ This is the last issue of 2023 - I wish you happy holidays, and see you in January ☃️

What if you could instantly resolve a critical issue in prod, with ]]></description>
        <link>https://ioscodereview.com/issues/61/</link>
        <guid isPermaLink="false">6571b6ebe2fb0d000167d8b1</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 07 Dec 2023 05:38:43 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 61st issue of iOS Code Review! Here's to another round of curated learnings ☺️ This is the last issue of 2023 - I wish you happy holidays, and see you in January ☃️</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">What if you could instantly resolve a critical issue in prod, with a single click? Rollbacks by Runway allows you to do just that. <br><br><b><strong style="white-space: pre-wrap;">Runway</strong></b> automatically re-signs your previous live production build and preps it for a possible rollback release — including preemptive submission for review — to remove all sources of stress and delay. Runway is the first platform to enable rollbacks for native mobile apps.<br><br><a href="https://www.runway.team/rollbacks?ref=ioscodereview.com" rel="noreferrer">Try Runway for free</a></div></div><h2 id="uiviewcontroller-viewisappearing">UIViewController viewIsAppearing</h2><p>Unlike <code>viewWillAppear</code>,&nbsp;by the time&nbsp;<code>viewIsAppearing</code>&nbsp;is called, the view has been added to the view hierarchy, has accurate geometry, including size and safe area insets.&nbsp;Available from iOS 13! <br>Using this method, it's a breeze to add animations to the content of the view controller that have to execute when the view first gets shown.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ohmyswift.com/blog/2023/12/01/from-viewwillappear-to-viewisappearing-perfecting-your-ios-view-transitions/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">From viewWillAppear to viewIsAppearing - Perfecting Your iOS View Transitions</div><div class="kg-bookmark-description">In WWDC23, Apple introduced a nuanced addition to the UIViewController lifecycle: viewIsAppearing. This instance method is a game-changer for developers looking to fine-tune the presentation and layout of their views. Let’s explore how this method enhances the way we build responsive and dynamic interfaces.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://ohmyswift.com/blog/assets/images/favicons/apple-touch-icon.png" alt=""><span class="kg-bookmark-author">OhMySwift</span><span class="kg-bookmark-publisher">Rizwan Ahmed A</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ohmyswift.com/blog/assets/images/viewIsAppearing/facebook.png" alt=""></div></a></figure><h2 id="catching-memory-leaks-on-ci">Catching memory leaks on CI</h2><p>It's annoying how easy it is to accidentally introduce memory leaks into our code. Just a little <code>self</code> sneaking into a closure past a code review, or an omitted <code>self</code> causing troubles when passing a method in place of a closure. We can add checks to unit tests verifying certain objects get deallocated, but it's not nearly possible to catch everything. We can use the <em>leaks</em> instrument (included with Xcode) to see if the app has any memory leaks at any given moment. </p><p>Here's a brilliant approach to automating catching leaks on CI:<br><em>1. Use a UI testing framework to simulate the flow in the application<br>2. Use the&nbsp;<code>leaks</code>&nbsp;tool provided by Apple to generate a&nbsp;<code>memgraph</code>.<br>3. Write a script to process the&nbsp;<code>generated memgraph</code>&nbsp;to check for leaks. If there any leaks are found, use&nbsp;<code>Danger</code>&nbsp;to mark the PR as failed or post a message to Slack.</em></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://levelup.gitconnected.com/automating-memory-leak-detection-with-ci-integration-for-ios-380f08a55f0b?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Automating Memory Leak Detection with CI Integration for iOS</div><div class="kg-bookmark-description">A solution to automate memory leak detection in iOS Development</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Level Up Coding</span><span class="kg-bookmark-publisher">Tuan Hoang (Eric)</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/1*aJxlDCpKAkwSY4SV1zCYLQ.jpeg" alt=""></div></a></figure><h2 id="opening-sfsafariviewcontroller-cleanly">Opening SFSafariViewController, cleanly</h2><p>In SwiftUI, we can utilize  <code>.openURL</code> environment variable to catch any element trying to open a link, and, for example, open it in an embedded browser instead. Moving that logic into a view modifier, the usage site becomes so clean 🤩 Check out Antoine's article for the full code. </p><pre><code>struct SwiftUILinksView: View {
    var body: some View {
        VStack(spacing: 20) {
            /// Creating a link using the `Link` View:
            Link("SwiftUI Link Example", destination: URL(string: "https://www.rocketsim.app")!)

            /// Creating a link using markdown:
            Text("Markdown link example: [RocketSim](https://www.rocketsim.app)")
        }
            /// This catches any outgoing URLs.
            .handleOpenURLInApp()
    }
}</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.avanderlee.com/swiftui/sfsafariviewcontroller-open-webpages-in-app/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">SFSafariViewController in SwiftUI: Open webpages in-app</div><div class="kg-bookmark-description">Use SFSafariViewController in SwiftUI and catch any outgoing URLs to ensure they open in-app instead of in the external Safari browser.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.avanderlee.com/wp-content/uploads/fbrfg/apple-touch-icon.png?v=2" alt=""><span class="kg-bookmark-author">SwiftLee</span><span class="kg-bookmark-publisher">Antoine van der Lee</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftlee-banners.herokuapp.com/imagegenerator.php?title=SFSafariViewController+in+SwiftUI%3A+Open+webpages+in-app" alt=""></div></a></figure><h2 id="ultimate-swiftdata-guide">Ultimate SwiftData guide</h2><p>For anyone looking for a clear roadmap for the journey of learning SwiftData, this is it. One of the longest articles I've ever seen, but you don't need to jump around a ton of different articles and WWDC videos. Although, I always recommend reading official documentation and watching official videos. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://azamsharp.com/2023/07/04/the-ultimate-swift-data-guide.html?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Ultimate Swift Data Guide</div><div class="kg-bookmark-description">The Ultimate Guide to Building SwiftData Applications</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">AzamSharp</span><span class="kg-bookmark-publisher">Mohammad Azam</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://azamsharp.com/images/ITeachOnTeachable.png" alt=""></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://www.runway.team/rollbacks?ref=ioscodereview.com" rel="noreferrer">Runway</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #60 ]]></title>
        <description><![CDATA[ Welcome to the 60th edition of iOS Code Review, just in time for the winter season! It&#39;s been an incredible journey through 60 issues, and I&#39;m grateful for your continued support. Thank you for being part of the iOS Code Review community! Here&#39;s to ]]></description>
        <link>https://ioscodereview.com/issues/60/</link>
        <guid isPermaLink="false">655f30b7ea1fb500017ed9c5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 23 Nov 2023 04:38:53 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Welcome to the 60th edition of iOS Code Review, just in time for the winter season! It's been an incredible journey through 60 issues, and I'm grateful for your continued support. Thank you for being part of the iOS Code Review community! Here's to another 60 issues of learning, sharing, and exploring the ever-evolving landscape of iOS development☕️</p><p>I'm excited to bring you another curated selection of learnings. Grab a warm beverage and dive in!</p><p>For this special issue, I'm happy to feature a set of tools built by my good twitter-friend Daniel Saidi. We've had parallel careers, in the same 4 years working as lead iOS developers in competing book subscription services in Scandinavia, and then going indie at the same time. I'm always happy to bring more recognition to indie tools, and I am grateful for Daniel's support of the newsletter ❤️</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">💎 Sponsor of the week - KeyboardKit Pro</strong></b><br><br>The<b><strong style="white-space: pre-wrap;"> KeyboardKit Pro</strong></b> SDK helps you build highly customizable keyboards for iOS. With support for 60+ languages and many powerful features, KeyboardKit Pro makes it easy to bring your functionality to brand new places.<br><br>Sign up for KeyboardKit Pro with discount code <b><strong style="white-space: pre-wrap;">BF23-KKPRO</strong></b> during Black Week to get <b><strong style="white-space: pre-wrap;">50%</strong></b> off your first purchase! <br><a href="https://keyboardkit.com/pro?ref=ioscodereview.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Get started for free 🚀</strong></b></a><br><br><i><em class="italic" style="white-space: pre-wrap;">Also check out </em></i><a href="https://kankoda.com/emojikit?ref=ioscodereview.com" rel="noreferrer"><i><em class="italic" style="white-space: pre-wrap;">EmojiKit</em></i></a><i><em class="italic" style="white-space: pre-wrap;"> to add powerful emoji features to your app, and </em></i><a href="https://kankoda.com/licensekit?ref=ioscodereview.com" rel="noreferrer"><i><em class="italic" style="white-space: pre-wrap;">LicenseKit</em></i></a><i><em class="italic" style="white-space: pre-wrap;"> to protect your closed-source software with commercial licenses.</em></i> Made by <a href="https://twitter.com/danielsaidi?ref=ioscodereview.com" rel="noreferrer">Daniel Saidi</a>.</div></div><h2 id="alternative-to-spacer">Alternative to Spacer</h2><p>Using a&nbsp;<code>.frame</code>&nbsp;modifier can save you a lot in performance over a&nbsp;<code>Spacer</code>, especially in lists or long horizontal/vertical stacks. David shares a number of scenarios where we can replace a <code>Spacer</code> with <code>.frame</code> and get the same behaviour:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://david.y4ng.fr/the-alternative-to-swiftui-spacer/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The alternative to SwiftUI’s Spacer</div><div class="kg-bookmark-description">Early on, SwiftUI introduced Spacer. But did you know that you can replace it with something else in most use cases?</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">David Yang</span><span class="kg-bookmark-publisher">David Yang</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://david.y4ng.fr/assets/images/2018/12/dya-circle.png" alt=""></div></a></figure><h2 id="pin-swiftui-view-to-an-edge">Pin SwiftUI view to an edge </h2><p>From iOS 15, there’s a handy&nbsp;<a href="https://developer.apple.com/documentation/swiftui/view/safeareainset(edge:alignment:spacing:content:)-6gwby?ref=ioscodereview.com">safeAreaInset</a>&nbsp;that allows us to place additional content extending the safe area. Without&nbsp;<code>safeAreaInset</code>, we'd have to manually calculate&nbsp;height of the additional content and adjust scroll view content insets manually. <code>safeAreaInset</code> is available from iOS 15 🙌</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://onmyway133.com/posts/how-to-show-anchor-bottom-view-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to show anchor bottom view in SwiftUI</div><div class="kg-bookmark-description">Issue #954
From iOS 15, there’s a handy safeAreaInset that allows us to place additional content extending the safe area. Shows the specified content beside the modified view. safeAreaInset allows us to customize which edge and alignment we can place our views. This works for both ScrollView, List…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://onmyway133.com/safari-pinned-tab.svg" alt=""><span class="kg-bookmark-author">Swift Discovery</span><span class="kg-bookmark-publisher">Khoa Pham</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://onmyway133.com/papermod-cover.png" alt=""></div></a></figure><h2 id="living-with-flaky-tests-temporarily">Living with flaky tests (temporarily)</h2><p>Sometimes tests are failing, and we can't fix them right away. That might be the case during a lengthy refactoring process, or we might have a flaky test that fails sometimes. <br>While it's a viable workaround to re-run the flaky test, or comment out failing ones, <code>XCTest</code> has an <code>XCTExpectedFailure</code> API that allows a test to fail temporarily:</p><pre><code class="language-swift">let options = XCTExpectedFailure.Options()
options.isStrict = false
XCTExpectFailure("Working on a fix for this intermittent problem.", options: options)
XCTAssertTrue(true, "This always works.")
XCTAssertTrue(testResultOfSomeActivity, "This only seems to work half the time.")</code></pre><p>Read Leonardo's article that goes in depth on various scenarios when this API could be useful:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://holyswift.app/unit-test-expected-failures-in-swift/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Unit Test Expected Failures in Swift - Holy Swift</div><div class="kg-bookmark-description">Explore managing expected failures in Swift’s XCTest with expert insights on balancing hard and soft skills in iOS development.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://holyswift.app/wp-content/uploads/2022/02/cropped-Logo-v2-1-270x270.png" alt=""><span class="kg-bookmark-author">Holy Swift</span><span class="kg-bookmark-publisher">Leonardo Maia Pugliese</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://holyswift.app/wp-content/uploads/2023/11/Screenshot-2023-11-10-at-08.26.32-2.png" alt=""></div></a></figure><h2 id="reusable-components-without-extra-effort">Reusable components without extra effort</h2><p>Okay, almost :) The idea is to employ more generalised naming of types as a guide to whether the component is reusable in your code, and use variable names for context. Here's an example:</p><pre><code class="language-swift">// Before
let moneyBuddyCard = MoneyBuddyCard(...)
let adviceView = AdviceView(...)

// After
let moneyBuddyCard = DecoratedCardView(...)
let adviceView = DecoratedCardView(...)</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftindepth.com/articles/reusable-components/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Deliver reusable components without making them reusable</div><div class="kg-bookmark-description">Reusability and duplication are tough to balance. What if I told you that, sometimes, you don’t have to?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swiftindepth.com/favicon.ico" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.swiftindepth.com/assets/articles/reusable-components/opengraph.png" alt=""></div></a></figure><h2 id="writing-better-documentation">Writing better documentation</h2><p>Editing is an important step in the process of writing documentation. Google has crafted a short, yet comprehensive guide to elevate your technical writing skills. I was amazed by how applying these simple rules transforms my writing. <br>At the end there's an exercise to improve this bit of text: </p><blockquote>Determine whether or not you can simplify your document through the use of terminology that is equivalent but relatively shorter in length and therefore more easily comprehensible by your audience. It's important to make sure your document is edited before it is seen by your audience, which might include people that are less or more familiar with the matter covered by your document. The first thing you need is a rough draft. Some things that can help make your document easier to read are making sure you have links to background information, and also checking for active voice instead of passive voice. If you have long sentences you can consider shortening them or implementing the use of a list to make the information easier to scan.</blockquote><p>I encourage you to try the exercise, and share your results! </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developers.google.com/tech-writing/two/editing?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Self-editing | Technical Writing | Google for Developers</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.gstatic.com/devrel-devsite/prod/va65162e8ce9aacc75e4d3c0cd6d166fc6ceaaf184fea0ff0eac1d9b62c0480be/developers/images/favicon-new.png" alt=""><span class="kg-bookmark-author">Google for Developers</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.gstatic.com/devrel-devsite/prod/va65162e8ce9aacc75e4d3c0cd6d166fc6ceaaf184fea0ff0eac1d9b62c0480be/developers/images/opengraph/white.png" alt=""></div></a></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://keyboardkit.com/pro?ref=ioscodereview.com" rel="noreferrer">Daniel with KeyboardKit</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #59 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 59th issue of iOS Code Review. I hope you find something interesting for you today ☺️

💎 Mobile DevOps Health Check - the first industry benchmarking tool

How well does your Mobile DevOps team perform? Take the quick Mobile DevOps Health Check to find out how mature ]]></description>
        <link>https://ioscodereview.com/issues/59/</link>
        <guid isPermaLink="false">654ccd057f541a00017707b6</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 09 Nov 2023 05:26:49 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 59th issue of iOS Code Review. I hope you find something interesting for you today ☺️ </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">💎 Mobile DevOps Health Check - the first industry benchmarking tool<br><br>How well does your Mobile DevOps team perform? Take the quick Mobile DevOps Health Check to find out how mature your team is and how you compare against the industry’s top-performing apps.<br><br><a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Take the 6-question Health Check</a></div></div><h2 id="swift-algorithmssplit-an-array-into-chunks-and-more">Swift Algorithms - split an array into chunks, and more</h2><p>If you google "how to split an array into chunks in Swift", you'll get a bunch of results showing how to implement a function that can split an array, called <code>chunked()</code>. <br>Another example we commonly need is removing duplicate elements from an array. </p><p>However implementing these function by yourself is not ideal  (and having to write all the unit tests!). Gladly many such functions are already provided by Apple, in a lesser known package called <code>swift-algorithms</code>. </p><p><code>swift-algorithms</code> package has various functions that are not (yet) included in the standard library. As for the reason why these functions are not in the standard library, the announcement post on swift.org sheds some light: </p><p><em>It’s our ambition for the standard library to include a rich, pragmatic set of generic algorithms. We think the&nbsp;<code>Algorithms</code>&nbsp;package can help realize this goal by serving as a low-friction venue to build out new families of related algorithms—giving us an opportunity to iteratively explore the problem space and learn how different algorithms connect and interact—before graduating them into the standard library.</em></p><p>Aside from <code>.chunked()</code> and <code>.unique()</code>, the package contains many other useful algorithms such as:</p><ul><li>creating permutations from elements in a collection</li><li>rotation of elements in an array</li><li>selecting a random part of a collection</li><li>getting a certain number of min/max elements</li><li>&nbsp;iteration over tuples of adjacent elements</li><li>and many more</li></ul><p>There are a number of benefits to using this package - each algorithm is thoroughly tested, peer reviewed, and improved for best possible performance, which is also documented for each algorithm. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swift.org/blog/swift-algorithms/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Announcing Swift Algorithms</div><div class="kg-bookmark-description">I’m excited to announce Swift Algorithms, a new open-source package of sequence and collection algorithms, along with their related types.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swift.org/apple-touch-icon-180x180.png" alt=""><span class="kg-bookmark-author">Swift.org</span><span class="kg-bookmark-publisher">Apple Inc.</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swift.org/apple-touch-icon-180x180.png" alt=""></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/apple/swift-algorithms?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - apple/swift-algorithms: Commonly used sequence and collection algorithms for Swift</div><div class="kg-bookmark-description">Commonly used sequence and collection algorithms for Swift - GitHub - apple/swift-algorithms: Commonly used sequence and collection algorithms for Swift</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">apple</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/10a39b5cfd0ef818b82960cbb89b59c06ec42306a2a3392d275e6344c370dffc/apple/swift-algorithms" alt=""></div></a></figure><h2 id="split-a-list-by-month">Split a list by month</h2><p>The <code>chunked()</code> function from <code>swift-algorithms</code> is not only allowing to split an array into fixed-size chunks. It also has a variant that allows to provide a custom decision-making closure for when a chunk should end. <br>Danijela is show casing an example of splitting a list of travel destinations grouped by month. Just be wary that for large amounts of data, it's better to utilise database-backed queries. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.danijelavrzan.com/posts/2023/10/swift-algorithms-chunked/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Split your data easily and efficiently with .chunked() | Danijela’s blog</div><div class="kg-bookmark-description">Swift Algorithms is an open source package of sequence and collection algorithms. It contains many generic algorithms found in other popular programming languages. In this post, we’ll take a look at how to implement the .chunked() algorithm to chunk an array of data and display it in your UI.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.danijelavrzan.com/images/favicon.png" alt=""><span class="kg-bookmark-author">Danijela's blog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.danijelavrzan.com/images/posts/2023/10/swift-algorithms-chunked.png" alt=""></div></a></figure><h2 id="geometryreaderblessing-or-curse">GeometryReader - Blessing or Curse?</h2><p>Some swear by GeometryReader, and some hate it to the bone. Or maybe you haven't had to use it at all. Whichever it is, this comprehensive article will be useful. <br>The author dives as deep as one can - with benefits and drawbacks, why it works the way it works, and how to hold it right. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://betterprogramming.pub/geometryreader-blessing-or-curse-1ebd2d5005ec?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GeometryReader: Blessing or Curse?</div><div class="kg-bookmark-description">A good tool is only as good as the person who wields it</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Better Programming</span><span class="kg-bookmark-publisher">fatbobman ( 东坡肘子)</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/1*tLh1QGOif1hoR3CIx0C9xw.jpeg" alt=""></div></a></figure><h2 id="setneedslayout-vs-layoutifneeded">setNeedsLayout() vs layoutIfNeeded() </h2><p>On the topic of layouts, here's one for UIKit. You'd use <code>layoutIfNeeded()</code> for an immediate update, and <code>setNeedsLayout</code> if you don't mind your changes to be animated. </p><p><em>setNeedsLayout():&nbsp;<br>This method does not force an immediate update, instead it marks the view for the update. It triggers the update during the next update cycle. This is efficient when you have multiple changes to make.<br><br>layoutIfNeeded():&nbsp;<br>This method forces the view to update its layout immediately. It ensures that all pending changes, if any, are applied immediately.</em></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.linkedin.com/posts/naman-sabarwal_demystifying-the-power-of-setneedslayout-ugcPost-7116986455033311232-oUtl/?utm_source=share&utm_medium=member_ios"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Learn the magic of setNeedsLayout() vs layoutIfNeeded() with Nitin Aggarwal. | Naman Sabarwal posted on the topic | LinkedIn</div><div class="kg-bookmark-description">Demystifying the power of setNeedsLayout() vs layoutIfNeeded() setNeedsLayout(): This method does not force an immediate update, instead it marks the view…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.licdn.com/aero-v1/sc/h/al2o9zrvru7aqj8e1x2rzsrca" alt=""><span class="kg-bookmark-author">LinkedIn</span><span class="kg-bookmark-publisher">Naman Sabarwal</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://media.licdn.com/dms/image/D4D05AQEAy3FWotSvlQ/feedshare-thumbnail_720_1280/0/1696821799016?e=2147483647&amp;v=beta&amp;t=OG1TyNuhkZsmzMMfN16yqYIE938nYNxFcyBFJSU7b0A" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!<br><br>Thank you to <a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Bitrise</a> for sponsoring yet another issue ❤️  </p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #58 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 58th issue of iOS Code Review. I hope you find something interesting for you today ☺️

💎 Mobile DevOps Health Check - the first industry benchmarking tool

How well does your Mobile DevOps team perform? Take the quick Mobile DevOps Health Check to find out how mature ]]></description>
        <link>https://ioscodereview.com/issues/58/</link>
        <guid isPermaLink="false">653a41f87950e100011ab1a8</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 26 Oct 2023 04:38:39 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 58th issue of iOS Code Review. I hope you find something interesting for you today ☺️ </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">💎 Mobile DevOps Health Check - the first industry benchmarking tool<br><br>How well does your Mobile DevOps team perform? Take the quick Mobile DevOps Health Check to find out how mature your team is and how you compare against the industry’s top-performing apps.<br><br><a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Take the 6-question Health Check</a></div></div><p>Sponsors help me grow my content creation and keep the lights up, so if you have time please make sure to have a look at the survey they're offering ☺️  </p><h2 id="how-not-to-monitor-swiftui-state">How (not) to monitor SwiftUI @State</h2><p>It might be tempting to use <code>didSet</code> to observe variables declared with <code>@State</code>, especially that it seems to work in the basic cases. But it doesn't work when the binding is passed to another view. We need to use the <code>.onChange</code> modifier to observe the variable. I met Dean at NSSpain this year, and I'm happy to share his blog with you all ☺️</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.thomasdurand.fr/story/2023-10-21-how-not-to-monitor-swiftui-state/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How (not) to monitor SwiftUI @State</div><div class="kg-bookmark-description">While I was working on the first version of my latest app SharePal ⚡️, I figured that I&amp;rsquo;d like to add haptic feedback for distinct action within the app.
Something that did not worked well… Since I&amp;rsquo;m targeting iOS&nbsp;16 as a base, I…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.thomasdurand.fr/icon.svg" alt=""><span class="kg-bookmark-author">Dean’s blog</span><span class="kg-bookmark-publisher">Thomas Durand</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.thomasdurand.fr/img/cover_huea95f719576bcab793980bcdacdf5346_33147_903ab47c6c87faeba9516b273145f7bb.png" alt=""></div></a></figure><h2 id="random-enum-case">Random enum case</h2><p>Such elegant solution for accessing a random case of an enum. Here's a gist of it, by a adding a simple extension on <code>CaseIterable</code>, any enum gets such functionality. You can read more about it in Jordan's blog post below.</p><pre><code class="language-swift">enum Foo: String, CaseIterable {
    case a, b, c
}

print(Foo.randomCaseIterableElement())</code></pre><pre><code class="language-swift">extension CaseIterable {
  public static func randomCaseIterableElement(using generator: inout some RandomNumberGenerator) -&gt; Self? {
    allCases.randomElement(using: &amp;generator)
  }

  public static func randomCaseIterableElement() -&gt; Self? {
    var generator = SystemRandomNumberGenerator()
    return randomCaseIterableElement(using: &amp;generator)
  }
}</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftjectivec.com/swift-randomnumbergenerator/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Generating Random Numbers Elegantly in Swift</div><div class="kg-bookmark-description">Swift has a useful mechanism to generate random values. Today, let’s see how we can plug in SystemRandomNumberGenerator for our own types.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swiftjectivec.com/swift-randomnumbergenerator/mstile-310x310.png" alt=""><span class="kg-bookmark-author">Jordan Morgan</span><span class="kg-bookmark-publisher">Jordan Morgan</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftjectivec.com/assets/images/logo.png" alt=""></div></a></figure><h2 id="launching-a-swiftui-view-from-the-terminal">Launching a SwiftUI view from the terminal</h2><p><em>"While there is a lot you can display in the terminal, there is certain information that is better conveyed in a graphical user interface. Contrary to what you might think, you&nbsp;don't need to create a full-blown macOS app&nbsp;to display a simple UI."</em></p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.polpiella.dev/launching-a-swiftui-view-from-the-terminal/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Launching a SwiftUI view from the terminal</div><div class="kg-bookmark-description">Learn how to launch a SwiftUI view directly from your Swift command-line tool without making a full-blown macOS application.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.polpiella.dev/assets/profile.png" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.polpiella.dev/api/thumbnail?title=Launching%20a%20SwiftUI%20view%20from%20the%20terminal" alt=""></div></a></figure><h2 id="writing-better-unit-tests">Writing better unit tests</h2><p>A collection of before-and-after examples that demonstrate how to enhance test cases by verifying prerequisites and conditions.</p><pre><code class="language-swift">verify(StorageThing)
    .hasNoEntry("something")
sut = UnitBeingTested()
verify(StorageThing)
    .hasEntry("something")</code></pre><p>In this example, the first line brings a benefit of verifying that the mocked storage didn't have the value before. Otherwise, the test would succeed even if initialising <code>sut</code> didn't save the value. <br>You can find many more examples like that in the article:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.devgenius.io/writing-good-unit-tests-2158be9ee82d?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Writing good unit tests</div><div class="kg-bookmark-description">We write tests to prove that our code is correct now and in the future. If we want to do some refactoring some day then we can rely on…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Dev Genius</span><span class="kg-bookmark-publisher">Chris Mash</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1024/1*XtizSuT5TMvXTuMpLTf0Gg.jpeg" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!<br><br>Thank you to <a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Bitrise</a> for sponsoring yet another issue ❤️  </p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #57 ]]></title>
        <description><![CDATA[ Hi friends, welcome to the 57th issue of iOS Code Review!
Today I&#39;m sharing three tips and three videos with you - as finally some conference recordings are available.
Enjoy the reading and watching! ☕️☕️

💎 Mobile DevOps Health Check - the first industry benchmarking tool

How well does your ]]></description>
        <link>https://ioscodereview.com/issues/57/</link>
        <guid isPermaLink="false">6527c81bb801b800017058e9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 12 Oct 2023 04:48:38 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi friends, welcome to the 57th issue of iOS Code Review! <br>Today I'm sharing three tips and three videos with you - as finally some conference recordings are available. <br>Enjoy the reading and watching! ☕️☕️</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text">💎 Mobile DevOps Health Check - the first industry benchmarking tool<br><br>How well does your Mobile DevOps team perform? Take the quick Mobile DevOps Health Check to find out how mature your team is and how you compare against the industry’s top-performing apps.<br><br><a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Take the 6-question Health Check</a></div></div><h2 id="onappear-vs-task">onAppear vs task</h2><p>If you'd like to execute code when a SwiftUI view becomes visible, you have the option of using either <code>onAppear</code> or <code>task</code>. They're not the same though: </p><ul><li><code>onAppear</code> is executed before the view is rendered the first time. At this point,  changes to the view state can be applied without causing any visible flickers, as the view will render with the new state.</li><li><code>task</code> is executed right after the view appears, so if any state changes are made, they are applied after the initial rendering. </li></ul><p>Chris Eidhof has created a sample code that demonstrates the difference, you can find it in his article: <a href="https://chris.eidhof.nl/post/swiftui-on-appear-vs-task/?ref=ioscodereview.com" rel="noreferrer">Running Code When Your View Appears</a>. <br>I learned about this from another newsletter <a href="https://not-only-swift.peterfriese.dev/issues/43?ref=ioscodereview.com" rel="noreferrer">Not Only Swift</a> made by Peter Friese 👋</p><h2 id="viewisappearingnew-in-ios-17">viewIsAppearing - new in iOS 17</h2><p>On the topic of views appearing, we there's an improvement in UIKit this year. We got a new view controller lifecycle method - <a href="https://developer.apple.com/documentation/uikit/uiviewcontroller/4195485-viewisappearing?ref=ioscodereview.com" rel="noreferrer"><code>viewIsAppearing</code> (documentation)</a>. </p><p>The primary distinction between <code>viewWillAppear</code> and <code>viewIsAppearing</code> lies in the timing of the callback. The new method is called after the view is added to the hierarchy and got accurate geometry. This means that we can make calculations that depends on the view's geometry before the view appears. <br>Previously the only option was to use <code>viewWillLayoutSubviews</code> and <code>viewDidLayoutSubviews</code>, and it's not a straightforward solution, because these methods are called more than once. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/10/renderedDark2x-1684331865.png" class="kg-image" alt="" loading="lazy" width="544" height="1058"><figcaption><span style="white-space: pre-wrap;">from documentation</span></figcaption></figure><h2 id="theres-still-a-place-for-uikit">There's still a place for UIKit</h2><p>With the advent of SwiftUI, we're asking ourselves - in what scenarios is UIKit still relevant? <br>Apps heavily based on images are one example. There's nothing yet in SwiftUI that can beat a <code>UICollectionView</code> with a custom layout. <br>Map clustering is another example. If you need to cluster annotations on the map when the user zooms out, it's not currently possible with pure SwiftUI.</p><p>We can still make many screens in SwiftUI, while keeping image-heavy screens or overall navigation in UIKit. There's no key learning here, I just feel it's worth reiterating that not everything can be done in SwiftUI yet. </p><figure class="kg-card kg-embed-card"><div><blockquote class="twitter-tweet"><p lang="en" dir="ltr">We have decided at my company to rewrite core parts of our app into UIKit.  For a photo heavy collection view app like us, it just makes more sense.<br><br>Also lifecycle control, navigation and debugability is significantly easier with UIKit.<br><br>SwiftUI costs an innovation token.</p>— Mahyar McDonald (@mahyarm8) <a href="https://twitter.com/mahyarm8/status/1710401031027519689?ref_src=twsrc%5Etfw&ref=ioscodereview.com">October 6, 2023</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div></figure><h2 id="crafting-swift-code-thats-bug-free-by-design">Crafting Swift Code that's bug-free by design</h2><p>My talk, titled "Crafting Swift Code that's bug-free by design", was recorded at NSSpain and is finally available - and I'm happy to share it with you. <br>In case you've been following the newsletter for a while, some of the insights might be familiar. Nonetheless there's something for everyone. I'd love to hear what you found most useful 😊</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe width="200" height="113" src="https://www.youtube.com/embed/J3Sd7St7y7E?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Bug-Free by Design - Crafting Swift Code That Doesn’t Sting [NSSpain 2023]"></iframe><figcaption><p><span style="white-space: pre-wrap;">Bug-Free by Design - Crafting Swift Code That Doesn’t Sting by Marina Vatmakhter</span></p></figcaption></figure><h2 id="how-ios-apps-can-be-hacked-and-what-to-do-about-it">How iOS apps can be hacked, and what to do about it</h2><p>My favourite talk from NSSpain,<em> Hacking iOS Mobile Apps</em> by Kamil Borzym shows how a harmful third-party library can steal any data provided by the user, including passwords they type in the app. </p><p>Coincidentally, I presented a talk on this topic a year ago, showing how to<em> protect your app from malicious code in a third party library</em> - explaining why and how to vet third-party dependencies.<em> </em>So these two talks make a perfect combo :) </p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe src="https://player.vimeo.com/video/865559955?app_id=122963" width="426" height="240" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" title="4 - Hacking iOS Mobile Apps - Kamil Borzym"></iframe><figcaption><p><i><em class="italic" style="white-space: pre-wrap;">Hacking iOS Mobile Apps</em></i><span style="white-space: pre-wrap;"> by Kamal Borzym </span></p></figcaption></figure><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe width="200" height="113" src="https://www.youtube.com/embed/8jnizu04w-s?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Protecting your app from malicious code in a third party library"></iframe><figcaption><p><span style="white-space: pre-wrap;">Protecting your app from malicious code in a third party library by Marina Vatmakhter</span></p></figcaption></figure><p>You can also find <a href="https://vimeo.com/showcase/10672108?ref=ioscodereview.com" rel="noreferrer">all other talk recordings from NSSpain 2023 on Vimeo</a>. </p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://bitrise.io/learn/modas-health-check?utm_source=sponsorship&utm_medium=cpc&utm_campaign=modas-campaign-2023&utm_content=modas-health-check-ioscodereview" rel="noreferrer">Bitrise</a> for sponsoring yet another issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #56 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 56th issue of iOS Code Review!
Grab your favorite beverage (pumpkin spice or not), find a comfy spot, and dive into this week&#39;s newsletter. Let&#39;s learn together. Happy reading!

Join the Mobile DevOps Summit 2023 on Oct 4-5
A two-day, free ]]></description>
        <link>https://ioscodereview.com/issues/56/</link>
        <guid isPermaLink="false">65154fa4933b900001ae042d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 28 Sep 2023 04:24:10 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 56th issue of iOS Code Review! <br>Grab your favorite beverage (pumpkin spice or not), find a comfy spot, and dive into this week's newsletter. Let's learn together. Happy reading!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Join the Mobile DevOps Summit 2023 on Oct 4-5</strong></b><br>A two-day, free event with 40+ workshops and sessions brought to you by 50+ industry-leading speakers from eBay, Reddit, AWS and more. Learn from real-world examples of successful Mobile DevOps implementations.<br><br><a href="https://summit.bitrise.io/page/2783516/speakers?utm_source=sponsorship&utm_medium=cpc&utm_campaign=mobile-devops-summit-2023&utm_content=ioscodereviewQ3" target="_blank" rel="noreferrer">Check out our speaker list</a></div></div><h2 id="are-you-using-swiftdata">Are you using SwiftData?</h2><p>New and fancy alternative to CoreData is much easier to use, but it still has a learning curve. It's declarative, so <em>how</em> we declare the data makes a difference.<br>With enums in particular, adding raw values makes a huge difference on how the data is stored, so we can reduce database size and make requests faster. On small scales that might not have much difference, but with large amounts of data it's certainly an improvement.</p><figure class="kg-card kg-image-card kg-card-hascaption"><a href="https://twitter.com/azamsharp/status/1705918717790491016?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/F60Am0jWcAANqVF.jpeg" class="kg-image" alt="" loading="lazy" width="2000" height="1126" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/F60Am0jWcAANqVF.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/F60Am0jWcAANqVF.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2023/09/F60Am0jWcAANqVF.jpeg 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w2400/2023/09/F60Am0jWcAANqVF.jpeg 2400w" sizes="(min-width: 720px) 720px"></a><figcaption><a href="https://twitter.com/azamsharp/status/1705918717790491016?ref=ioscodereview.com" rel="noreferrer"><span style="white-space: pre-wrap;">Mohammad Azam on Twitter</span></a></figcaption></figure><h2 id="new-behaviour-of-urlstring-in-ios-17">New behaviour of URL(string:) in iOS 17</h2><p>If you're building your app using Xcode 15, <a href="https://developer.apple.com/documentation/foundation/url/3126806-init?ref=ioscodereview.com" rel="noreferrer"><code>URL(string:)</code></a> gets a new behaviour. Now invalid urls don't return <code>nil</code> anymore, and get percent-encoded. To get the old behaviour, we need to use <a href="https://developer.apple.com/documentation/foundation/url/4191020-init?ref=ioscodereview.com" rel="noreferrer"><code>URL(string: str, encodingInvalidCharacters: false)</code></a></p><figure class="kg-card kg-image-card kg-card-hascaption"><a href="https://twitter.com/developermaris/status/1701487361069031542?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/F5zkp1jWsAAMy2r.jpeg" class="kg-image" alt="" loading="lazy" width="1200" height="954" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/F5zkp1jWsAAMy2r.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/F5zkp1jWsAAMy2r.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/F5zkp1jWsAAMy2r.jpeg 1200w" sizes="(min-width: 720px) 720px"></a><figcaption><a href="https://twitter.com/developermaris/status/1701487361069031542?ref=ioscodereview.com" rel="noreferrer"><span style="white-space: pre-wrap;">Maris Lagzdins on Twitter</span></a></figcaption></figure><h2 id="how-to-make-a-strong-case-for-accessibility">How to make a strong case for accessibility</h2><p>As one example of accessibility not serving only disabled users, subtitles are not only for deaf users - they also serve those who can't listen at the moment, or are located in a loud environment. <br>A brilliant infographic, and a <a href="https://smart-interface-design-patterns.com/articles/accessibility-strong-case/?ref=ioscodereview.com" rel="noreferrer">brilliant article</a> with a set of practical takes on building a compelling case for supporting accessibility in our apps.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/01-accessibility-strong-case-2.jpg" class="kg-image" alt="" loading="lazy" width="2000" height="3317" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/01-accessibility-strong-case-2.jpg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/01-accessibility-strong-case-2.jpg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1600/2023/09/01-accessibility-strong-case-2.jpg 1600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/01-accessibility-strong-case-2.jpg 2000w" sizes="(min-width: 720px) 720px"></figure><h2 id="string-catalogs-in-xcode-15">String catalogs in Xcode 15</h2><p>Xcode 15 finally introduces a better way to handle localizations in a structured way. No more .strings files 😎 Here's a four-minute demo of the new functionality:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/0NRSfz6eTAI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Localization made easy with Xcode 15"></iframe></figure><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://summit.bitrise.io/page/2783516/speakers?utm_source=sponsorship&utm_medium=cpc&utm_campaign=mobile-devops-summit-2023&utm_content=ioscodereviewQ3" rel="noreferrer">Bitrise</a> for sponsoring this issue ❤️</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #55 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 55th issue of iOS Code Review!

Over the past two weeks, I had the privilege of attending iOSDevUK and speaking at NSSpain. It was an incredible experience! My talk, titled &quot;Crafting Swift Code that&#39;s bug-free by design&quot;, was recorded and will ]]></description>
        <link>https://ioscodereview.com/issues/55/</link>
        <guid isPermaLink="false">649423d8811e4e0001cac3c9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 19 Sep 2023 06:32:36 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 55th issue of iOS Code Review! </p><p>Over the past two weeks, I had the privilege of attending iOSDevUK and speaking at NSSpain. It was an incredible experience! My talk, titled "Crafting Swift Code that's bug-free by design", was recorded and will be available in the coming weeks - I will share it with you then.</p><p>I would like to take a moment to express my warmest welcome to those of you who I had the pleasure of meeting at iOSDevUK and NSSpain, and to everyone who have joined the iOS Code Review community recently. Your presence and engagement mean the world to me ❤️</p><p>Today I'm excited to share a few learnings that caught my attention at the conferences.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">💎</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Sponsor of the week: Paste</strong></b><br><br><b><strong style="white-space: pre-wrap;">Paste</strong></b> is a productivity app for Mac and iOS devices that amplifies the system’s clipboard capabilities. It’s a go-to tool for thousands of developers who aim to speed up their daily workflow.<br><br>Today we're launching Paste 4.0, ready for iOS 17! It has been rebuilt from the ground up, offering enhanced performance and a unified user experience across all platforms.<br><br><a href="https://pasteapp.io/?ref=ioscodereview.com"><b><strong style="white-space: pre-wrap;">Try for free</strong></b></a><b><strong style="white-space: pre-wrap;"> 😎</strong></b></div></div><p></p><hr><h2 id="cache-vs-persistent-store">Cache vs Persistent store</h2><p><strong>Avi Tsadok</strong> talked about building offline-first apps. When we build offline support in our app, it's important to note the difference between <em>caching</em> and <em>persistence. Caching</em> is temporary and it's main purpose is to boost performance and perceived speed of the app. Persistence, on the other hand, allows to operate on the data in offline, providing full offline capability to the app. So before we reach to pick a storage solution, we should understand - are we adding caching or persistence?</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7282--1-.jpeg" class="kg-image" alt="" loading="lazy" width="1280" height="618" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/IMG_7282--1-.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/IMG_7282--1-.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7282--1-.jpeg 1280w" sizes="(min-width: 720px) 720px"></figure><h2 id="simple-app-architecture">Simple app architecture</h2><p><strong>David Kababyan</strong> shared the architecture behind the iOSDevUK conference app. That was a lightnign talk, and the architecture seems nice for a small app like that!</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7309.jpeg" class="kg-image" alt="" loading="lazy" width="1280" height="668" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/IMG_7309.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/IMG_7309.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7309.jpeg 1280w" sizes="(min-width: 720px) 720px"></figure><h2 id="working-with-time">Working with time</h2><p><strong>Dave DeLong</strong> gave an insightful talk about working with dates, drawing an analogy with coordinates on the map. There are real places (points in time), and there are their names in a certain coordinate system or in a certain address system (epoch time, date representation in different calendars or time zones). </p><p>What I found particlularly interesting is the difference between <em>setting</em> and <em>offsetting</em> time. When we want to compose a date that means 3 am on a certain day, we have two ways of doing it: <br>- get the day and <em>set</em> its hour to '3 am'<br>- get the day's start (midnight) and <em>add</em> 3 hours. <br>The first might not exist, and the second will always exist.</p><p>And it's worth remembering that sometimes we don't need to bother, and <code>24*60*60</code> might be fine, for example if we're talking cache expiration.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7516.jpeg" class="kg-image" alt="" loading="lazy" width="1280" height="768" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/IMG_7516.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/IMG_7516.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7516.jpeg 1280w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7517.jpeg" class="kg-image" alt="" loading="lazy" width="1280" height="769" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/IMG_7517.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/IMG_7517.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7517.jpeg 1280w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7522.jpeg" class="kg-image" alt="" loading="lazy" width="1280" height="769" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/IMG_7522.jpeg 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/IMG_7522.jpeg 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/IMG_7522.jpeg 1280w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><a href="https://twitter.com/felibe444/status/1702757495452701093?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/image.png" class="kg-image" alt="" loading="lazy" width="1222" height="1322" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/image.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/image.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/image.png 1222w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="james-dempsey-and-the-breakpoints">James Dempsey and the Breakpoints</h2><p>NSSpain wrapped up with a bang - a performance by James Dempseys' country band - <em>James Dempsey and the Breakpoints</em>. The only band out there that sings about Swift Development 😄 check them out!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://jamesdempsey.org/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">James Dempsey and the Breakpoints - Backtrace</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://jamesdempsey.org/favicon.ico" alt=""><span class="kg-bookmark-author">Backtrace</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://jamesdempsey.org/img/album.jpg" alt=""></div></a></figure><h2 id="and-swift-59-is-here">and, Swift 5.9 is here!</h2><p>This is a major new release that introduces macros to Swift, adds bi-directional interoperability with C++, and more. <a href="https://www.swift.org/blog/swift-5.9-released/?ref=ioscodereview.com">Read the blog post to see what's new.</a> </p><p>Using if and switch as expressions is something many have waited for. Let's just try avoid writing code like this (via <a href="https://twitter.com/krzyzanowskim/status/1703839512000929909?ref=ioscodereview.com">@krzyzanowskim</a>):</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/image-1.png" class="kg-image" alt="" loading="lazy" width="1270" height="145" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/09/image-1.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/09/image-1.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/09/image-1.png 1270w" sizes="(min-width: 720px) 720px"></figure><hr><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to friends at <a href="https://pasteapp.io/?ref=ioscodereview.com">Paste</a> for sponsoring this issue ❤️</p><p>What was particularly interesting? let me know by replying!</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #54 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 54th issue of iOS Code Review!  Let&#39;s learn something new ☀️
It&#39;s confirmed - I&#39;m going to iOSDevUK and NSSpain 🎉  More details at the end of the email :)


Cleaner grid initialization

Here&#39;s Daniel with handy extensions for a ]]></description>
        <link>https://ioscodereview.com/issues/54/</link>
        <guid isPermaLink="false">64f06fcd12d2c400012936fa</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 31 Aug 2023 07:20:05 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 54th issue of iOS Code Review!  Let's learn something new ☀️ <br>It's confirmed - I'm going to <em>iOSDevUK and NSSpain 🎉  </em>More details at the end of the email :)</p><h2 id="cleaner-grid-initialization">Cleaner grid initialization</h2><p>Here's Daniel with handy extensions for a simpler way of defining  <code>LazyVGrid</code> and <code>LazyHGrid</code> 's columns:</p><pre><code class="language-swift">LazyVGrid(columns: .fixed(100)) { ... }
LazyVGrid(columns: [.fixed(100), .fixed(150)]) { ... }
LazyVGrid(columns: .adaptive(minimum: 100, maximum: 150)) { ... }</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://danielsaidi.com/blog/2023/08/30/cleaner-grid-initialization-in-swiftui?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Cleaner grid initialization in SwiftUI</div><div class="kg-bookmark-description">SwiftUI’s LazyVGrid and LazyHGrid are great for creating powerful and flexible grids, but I always struggle with how to define columns when creating them. I’ve therefore created some extensions to make this easier. Let’s take a look.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://danielsaidi.com/assets/icon/icon-1024.png" alt=""><span class="kg-bookmark-author">Daniel Saidi</span><span class="kg-bookmark-publisher">danielsaidi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://danielsaidi.com/assets/icon/icon-facebook.png" alt=""></div></a></figure><h2 id="analogue-clock-on-macos-in-swiftui">Analogue clock on macOS in SwiftUI</h2><p>Apparently, <code>DatePicker</code> on macOS can be fun, where the user can move clock hands to select a time 🙈</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/borto_ale/status/1697223179469549726?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/Xnapper-2023-08-31-15.50.05.png" class="kg-image" alt loading="lazy" width="1254" height="1002" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/08/Xnapper-2023-08-31-15.50.05.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/08/Xnapper-2023-08-31-15.50.05.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/Xnapper-2023-08-31-15.50.05.png 1254w" sizes="(min-width: 720px) 720px"></a></figure><figure class="kg-card kg-image-card"><a href="https://twitter.com/Jeehut/status/1697233997997256886?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/Xnapper-2023-08-31-15.51.06.png" class="kg-image" alt loading="lazy" width="1250" height="786" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/08/Xnapper-2023-08-31-15.51.06.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/08/Xnapper-2023-08-31-15.51.06.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/Xnapper-2023-08-31-15.51.06.png 1250w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="premature-optimization-universally-misunderstood">Premature Optimization: Universally Misunderstood</h2><p>The famous quote actually reads:</p><blockquote>We should forget about <strong>small efficiencies</strong>, say about 97% of the time: premature optimization is the root of all evil.<br>– Sir Tony Hoare</blockquote><p>Indeed, once an app is shipped to users, it can be too late to fundamentally change the app architecture, database structure, or API design. Those large aspects should be thought through early, and small optimizations can be done at a scaling stage.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://milen.me/writings/premature-optimization-universally-misunderstood/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">milen.me — Premature Optimization: Universally Misunderstood</div><div class="kg-bookmark-description">“Premature Optimization” You might have come across the famous software optimisation quote popularised by Donald Knuth:Premature optimization is the root of all evil.– Sir Tony HoareIt has been commonly interpreted as “don’t think about performance in the beginning, you can fix any performance pr…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://milen.me/images/favicons/milen.me-favicon-48.png" alt=""></div></div></a></figure><h2 id="co-authoring-git-commits">Co-authoring Git commits</h2><p>Git supports having multiple authors on a commit - so when you're pair-programming with a colleague, they can receive credit for it too. <br>We simply need to add the credit as extra text anywhere in the commit message - <code>Co-authored-by: &lt;name&gt; &lt;email&gt;</code> :</p><figure class="kg-card kg-image-card kg-card-hascaption"><a href="https://dev.to/cassidoo/co-authoring-git-commits-3gin?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image-3.png" class="kg-image" alt loading="lazy" width="548" height="210"></a><figcaption><a href="https://dev.to/cassidoo/co-authoring-git-commits-3gin?ref=ioscodereview.com">By Cassidy Williams</a></figcaption></figure><h2 id="tool-to-find-unused-code">Tool to find unused code</h2><p>TIL that there's a tool to find unused code, I always wished there was one. It's called <a href="https://github.com/peripheryapp/periphery?ref=ioscodereview.com">Periphery</a>. I learned about it via Manu, who wrote a nice article on how to set it up for your project:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.manu.show/2023-08-21-use-periphery-to-find-unused-code/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Use Periphery to find unused code</div><div class="kg-bookmark-description">From time to time, it might be a good idea to spend a couple of hours checking if there is some code in the codebase that is not being used anymore. Luckily for us, there is a tool out there that can make the job easier. Periphery: A tool to identify unused code in Swift projects. Using Periphery on…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.manu.show/favicon.ico" alt=""><span class="kg-bookmark-author">manu.show</span><span class="kg-bookmark-publisher">Manu Herrera</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://manu.show/resources/periphery/logo.png" alt=""></div></a></figure><hr><p>✌️</p><p>I will be at iOSDevUK on the main conference days -  5-7 September, and on NSSpain 14-16 September. If you're there - come say hi! <br>I'll have stickers to give away 😋  Do you also want a t-shirt with the newsletters logo? Send me your size and I'll pre-make one for you.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>Join the Mobile DevOps Summit 2023 on Oct 4-5</strong><br>A two-day, free event with 40+ workshops and sessions brought to you by 50+ industry-leading speakers from eBay, Reddit, AWS and more. Learn from real-world examples of successful Mobile DevOps implementations. <a href="https://summit.bitrise.io/page/2783516/speakers?utm_source=sponsorship&utm_medium=cpc&utm_campaign=mobile-devops-summit-2023&utm_content=ioscodereviewQ3">Check out our speaker list</a></div></div><p>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️</p><p></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #53 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 53rd issue of iOS Code Review! It&#39;s so nice to be back 🎉

It&#39;s almost conference season 🤓 I&#39;m going to a couple of conferences this autumn. I will speak at NSSpain and hopefully get a visa in time attend iOSDevUK. ]]></description>
        <link>https://ioscodereview.com/issues/53/</link>
        <guid isPermaLink="false">64dbbf30f2f91e0001a12b51</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 17 Aug 2023 04:03:56 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 53rd issue of iOS Code Review! It's so nice to be back 🎉</p><p>It's almost conference season 🤓 I'm going to a couple of conferences this autumn. I will speak at <em>NSSpain</em> and hopefully get a visa in time attend <em>iOSDevUK</em>. Will I see you there? Let me know if you're also planning to go, let's meet!<br>If you're not going to any in-person conferences, perhaps check out the online Mobile DevOps Summit by Bitrise, who are so kind to be sponsoring multiple issues of the newsletter ☺️</p><p>Also a small personal update: I've changed my last name to Vatmakhter - which is my grandparents family name. It's something I've been wanting to do for many years, and finally I could 🎉☺️ I'll slowly propagate it throughout my online presence - it's still me 😁</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>Join the Mobile DevOps Summit 2023 on Oct 4-5</strong><br>A two-day, free event with 40+ workshops and sessions brought to you by 50+ industry-leading speakers from eBay, Reddit, AWS and more. Learn from real-world examples of successful Mobile DevOps implementations. <a href="https://summit.bitrise.io/page/2783516/speakers?utm_source=sponsorship&utm_medium=cpc&utm_campaign=mobile-devops-summit-2023&utm_content=ioscodereviewQ3">Check out our speaker list</a></div></div><h2 id="enum-based-sheet-presentation">Enum-based sheet presentation</h2><p>Displaying multiple sheets from one view can quickly lead to repetitive code segments in SwiftUI. By using an enum to represent which sheet to present, we can make the code more maintainable. This, and more learnings can be found in Antoine's article below.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image.png" class="kg-image" alt loading="lazy" width="1356" height="2048" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/08/image.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/08/image.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image.png 1356w" sizes="(min-width: 720px) 720px"><figcaption>image source: <a href="https://twitter.com/twannl/status/1597940020597374976?ref=ioscodereview.com">@twannl</a></figcaption></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.avanderlee.com/swiftui/presenting-sheets/?utm_campaign=coschedule&utm_source=twitter&utm_medium=twannl&utm_content=Sheets%20in%20SwiftUI%20explained%20with%20code%20examples#enum-based-sheet-presentation"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Sheets in SwiftUI explained with code examples</div><div class="kg-bookmark-description">Sheets in SwiftUI allow you to present a view on top of another. Learn how you can control multiple sheets using a generic solution.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.avanderlee.com/wp-content/uploads/fbrfg/apple-touch-icon.png?v&#x3D;2" alt=""><span class="kg-bookmark-author">SwiftLee</span><span class="kg-bookmark-publisher">Antoine van der Lee</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftlee-banners.herokuapp.com/imagegenerator.php?title&#x3D;Sheets+in+SwiftUI+explained+with+code+examples" alt=""></div></a></figure><h2 id="using-error">Using #error</h2><p>Swift has a compiler directive that allows us to issue a compilation error. <br>This can be useful in a few ways, for example to prevent the app from compiling in certain conditions.<br>One of my usecases is when you're iterating over a feature and want to merge to <code>develop</code>, and want to make sure the app can't be released in an unfinished state. </p><pre><code class="language-Swift">func calculateStuff() {
    print("TBD")
#if RELEASE
    #error("calculateStuff feature is not implemented!"
#endif
}</code></pre><p>Here's <a href="https://www.swiftwithvincent.com/blog/discover-hash-sign-error?ref=ioscodereview.com">Vincent sharing</a> another scenario, where package authors can use <code>#error</code> in their example code, to bring user's attention where they need to fill out the api key.</p><h2 id="text-text">Text + Text</h2><p>A handly alternative to <code>AttributedString</code> in SwiftUI:</p><figure class="kg-card kg-image-card"><a href="https://mastodon.social/@ramzesenok/110332050551344694?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image-1.png" class="kg-image" alt="SwiftUI lets us to compile Texts using the + operator. You can apply certain modifiers (that return type is Text) to Texts and it still will work.  You can use string interpolation and put one Text into another one. And since SFSymbols are also text you can embed them too" loading="lazy" width="1386" height="1142" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/08/image-1.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/08/image-1.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image-1.png 1386w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="a-refactoring-story">A refactoring story</h2><p>Every codebase has a piece of code similar to this. Here's Jon demonstrating a step-by step refactoring to make it error-proof:</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image-2.png" class="kg-image" alt loading="lazy" width="1554" height="622" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/08/image-2.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/08/image-2.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/08/image-2.png 1554w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://qualitycoding.org/refactoring-cleaning-mess/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Refactoring: How Do You Clear Up a Mess, Safely? | Quality Coding</div><div class="kg-bookmark-description">When refactoring in small steps, sometimes you have to make a mess to clear up a mess. Download the code and walk through these refactoring steps.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://qualitycoding.org/wp-content/uploads/2020/06/favicon.png" alt=""><span class="kg-bookmark-author">Quality Coding</span><span class="kg-bookmark-publisher">Jon Reid</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://qualitycoding.org/wp-content/uploads/2018/12/social-refactoring-mess-safely-scaled.jpg" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Let's spread the good code vibes ✨🧘🌈☀️<br>Thank you to <a href="https://summit.bitrise.io/page/2783516/speakers?utm_source=sponsorship&utm_medium=cpc&utm_campaign=mobile-devops-summit-2023&utm_content=ioscodereviewQ3">Bitrise</a> for sponsoring this issue ❤️<br>And I always want to hear from you -just reply to this email :) </p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #52 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 52nd issue of iOS Code Review! Grab a quick cup of your favorite beverage and let&#39;s learn something new :)

Setapp offers a collection of 240+ carefully curated macOS apps under one subscription. Now there&#39;s no need to purchase individual subscriptions for ]]></description>
        <link>https://ioscodereview.com/issues/52/</link>
        <guid isPermaLink="false">64a6dadb9bee9e000188910d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 06 Jul 2023 11:35:01 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 52nd issue of iOS Code Review! Grab a quick cup of your favorite beverage and let's learn something new :) </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>Setapp</strong> offers a collection of 240+ carefully curated macOS apps under one subscription. Now there's no need to purchase individual subscriptions for each app.<br><br><strong><a href="https://setapp.sjv.io/c/4300314/343321/5114?ref=ioscodereview.com">Try Setapp for free 🚀&nbsp;</a></strong></div></div><h2 id="gifs-in-swiftui">GIFs in SwiftUI</h2><p>TIL how easy it is to play gif animations in UIKit and SwiftUI using <code><a href="https://developer.apple.com/documentation/imageio/3333271-cganimateimageaturlwithblock?ref=ioscodereview.com">CGAnimateImageAtURLWithBlock</a></code>. We just need to remember to stop the animation when the view disappears:</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/JordanMorgan10/status/1676679189850619905?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-20.16.07.png" class="kg-image" alt loading="lazy" width="1122" height="1598" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/07/Xnapper-2023-07-06-20.16.07.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/07/Xnapper-2023-07-06-20.16.07.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-20.16.07.png 1122w" sizes="(min-width: 720px) 720px"></a></figure><figure class="kg-card kg-image-card"><a href="https://twitter.com/safeAreaInsets/status/1676765881240788993?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-19.38.12.png" class="kg-image" alt loading="lazy" width="1128" height="872" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/07/Xnapper-2023-07-06-19.38.12.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/07/Xnapper-2023-07-06-19.38.12.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-19.38.12.png 1128w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="view-vs-view-modifier">View vs View modifier?</h2><p>Back when I just started learning SwiftUI, I started by making all of my customizations as <code>View</code>. I even had styled text as a <code>View</code> wrapping a styled <code>Text</code>, similar to <code>UILabel</code> subclasses in UIKit 🙈🙈<br>Fairly quickly though I grasped the idea of view modifiers, still using custom <code>View</code>s for breaking down the view hierarchy and for reusable components.</p><p>So when I stumbled on John's article where he explores when to use what approach, I knew I have to share it with you folks. He implements the same "featured" UI using a view and a view modifier, and compares them side by side:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftbysundell.com/articles/swiftui-views-versus-modifiers/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">SwiftUI views versus modifiers | Swift by Sundell</div><div class="kg-bookmark-description">What’s really the difference between building a piece of UI as a view versus a modifier, and how to choose between those two solutions?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.swiftbysundell.com/images/favicon.png" alt=""><span class="kg-bookmark-author">Swift by Sundell</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.swiftbysundell.com/images/articles/swiftui-views-versus-modifiers.png" alt=""></div></a></figure><h2 id="beware-of-xcodes-automatic-version-management">Beware of Xcode's automatic version management</h2><p>Alexander shares his surprising experience with Xcode's ability to override version and build numbers during app export. Turns out, it overrides the values in all Info.plist files, including those embedded in third-party SDKs, so you can run into subtle issues if the SDK is checking those values. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://alexanderweiss.dev/blog/2023-07-04-appstore-connect-manage-app-version-and-build-number?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">AppStore Connect: Manage Version and build number</div><div class="kg-bookmark-description">I have released quite a few apps already, mostly at work but also personally. When releasing, I was facing issues with signing, Xcode configurations, CI/CD solutions or the AppStore Review. I assumed I have seen quite a lot of issues. Recently I was…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://alexanderweiss.dev/favicon.ico" alt=""><span class="kg-bookmark-author">Teabyte</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://personal-site-m1o4rkp20-alexanderwe.vercel.app/blog/2023-07-04-appstore-connect-manage-app-version-and-build-number/opengraph-image?14678ee0ab859fb4" alt=""></div></a></figure><h2 id="looking-up-apples-error-codes">Looking up Apple's error codes </h2><p>Save it for later -&gt; <a href="https://www.osstatus.com/search/results?platform=all&framework=all&search=12&ref=ioscodereview.com">osstatus.com</a></p><figure class="kg-card kg-image-card"><a href="https://twitter.com/chrisvasselli/status/1603001083353341954?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-20.05.23.png" class="kg-image" alt loading="lazy" width="1122" height="674" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/07/Xnapper-2023-07-06-20.05.23.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/07/Xnapper-2023-07-06-20.05.23.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/07/Xnapper-2023-07-06-20.05.23.png 1122w" sizes="(min-width: 720px) 720px"></a></figure><p>✌️<br>Alright, that's it for today.<br>PS. As Twitter has messed up its API, I still have to embed tweets using screenshots. I'd love to hear your experience with images in the emails - how has that been, are you experiencing any issues with that? Let me know 🙏</p><p><em>* this issue contains an affiliate link to <a href="https://setapp.sjv.io/c/4300314/343321/5114?ref=ioscodereview.com">Setapp</a></em></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #51 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 51st issue of iOS Code Review! I hope the summer is treating you well ☀️ Let&#39;s learn something new!

💎Announcing the Mobile DevOps Summit 2023 | Oct 4-5

Join 4500+ fellow mobile DevOps practitioners virtually for a two-day event packed with the latest trends, best ]]></description>
        <link>https://ioscodereview.com/issues/51/</link>
        <guid isPermaLink="false">6494288f811e4e0001cac401</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 22 Jun 2023 06:14:57 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 51st issue of iOS Code Review! I hope the summer is treating you well ☀️ Let's learn something new! </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">💎</div><div class="kg-callout-text"><b>Announcing the Mobile DevOps Summit 2023 | Oct 4-5</b><br><br>Join 4500+ fellow mobile DevOps practitioners virtually for a two-day event packed with the latest trends, best practices, and hands-on workshops from the industry experts. Register for free today!<br><br><a href="https://summit.bitrise.io/?utm_source=sponsorship_ioscodereview&utm_medium=email&utm_campaign=mobile-devops-summit-2023&utm_content=invitation">Register for free</a></div></div><h2 id="check-your-third-party-dependencies">Check your third party dependencies</h2><p>Last year I gave a talk on Mobile DevOps Summit 2022 about protecting your app from malicious code in third party libraries. That's also why I'm extra excited that they're sponsoring the newsletter 😄 <br>In short, code in a framework gets access to your whole view hierarchy and memory, so they could steal your user's data. In the talk I give tips on how to check that a library isn't doing what it isn't supposed to.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/8jnizu04w-s?list=PLbKJc0NMPDrB29Ir8q8ABVOyJJZzkUwEN" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></figure><p>You can find all recordings from last year <a href="https://www.youtube.com/playlist?list=PLbKJc0NMPDrB29Ir8q8ABVOyJJZzkUwEN&ref=ioscodereview.com">on Youtube</a>.</p><h2 id="shuffling-arrays">Shuffling arrays</h2><p>Don't know who needs to hear this, but there's a set of handy methods for randomly shuffling any array. <br>There's <code>shuffle()</code> and <code>shuffled()</code>, and companion methods that take a random number generator. A custom generator can implement, for example, a reproducible ordering - while the default one (<code>SystemRandomNumberGenerator</code>) makes it as random as it can be:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/swift/array/shuffled(using:)?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">shuffled(using:) | Apple Developer Documentation</div><div class="kg-bookmark-description">Returns the elements of the sequence, shuffled using the given generator as a source for randomness.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><h2 id="on-skipping-tests">On skipping tests</h2><p>How does Xcode know which tests to execute? It looks for classes conforming to <code>XCTestCase</code>, and inside them for any method starting with <code>test</code>. <br>So one way to temporarily disable a test is to comment out or rename the method so it doesn't start with <code>test</code>. <br>There's a better way though - we can conditionally skip tests by calling <code>XCTSkip</code>, <code>XCTSkipIf</code> and <code>XCTSkipUnless</code> :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.wwdcnotes.com/notes/wwdc20/10164/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">XCTSkip your tests | WWDC NOTES</div><div class="kg-bookmark-description">Get the test results that matter — and skip the ones that don’t. Discover how you can implement XCTSkip to conditionally avoid tests at runtime. We’ll take you through how to return this new test result and better document tests beyond pass and fail within your test bundle. To get the most out of t…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.wwdcnotes.com/images/favicon/favicon.png" alt=""><span class="kg-bookmark-author">WWDC NOTES</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.wwdcnotes.com/images/social/wwdc2020-10164.png" alt=""></div></a></figure><h2 id="swift-macrossomethings-coming">Swift Macros - something's coming!</h2><p>Swift Macros are so powerful, I'm yet to comprehend how much they will change the way we do things in Swift. I'm looking forward to using them in production apps starting from September. <br>Here's two down-to-earth examples where they can simplify our coding life:</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/Lee_Kah_Seng/status/1671412791310266371?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-22-15.10.37.png" class="kg-image" alt loading="lazy" width="1048" height="944" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/06/Xnapper-2023-06-22-15.10.37.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/06/Xnapper-2023-06-22-15.10.37.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-22-15.10.37.png 1048w" sizes="(min-width: 720px) 720px"></a></figure><figure class="kg-card kg-image-card"><a href="https://twitter.com/azamsharp/status/1671362475722174465?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-22-15.12.22.png" class="kg-image" alt loading="lazy" width="1148" height="1684" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/06/Xnapper-2023-06-22-15.12.22.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/06/Xnapper-2023-06-22-15.12.22.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-22-15.12.22.png 1148w" sizes="(min-width: 720px) 720px"></a></figure><p>✌️<br>Alright, that's it for today! <br>Thank you to <a href="https://summit.bitrise.io/?utm_source=sponsorship_ioscodereview&utm_medium=email&utm_campaign=mobile-devops-summit-2023&utm_content=invitation">Bitrise Mobile DevOps Summit</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #50 👑 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 50th issue of iOS Code Review, and happy WWDC week! I hope you&#39;re not too overwhelmed. Please enjoy today&#39;s issue which doesn&#39;t talk about what&#39;s new this year 😁

💎 Sponsor of the week - Bitrise

Last year Bitrise ]]></description>
        <link>https://ioscodereview.com/issues/50/</link>
        <guid isPermaLink="false">647f2e939d2a890001992912</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Fri, 09 Jun 2023 03:49:04 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 50th issue of iOS Code Review, and happy WWDC week! I hope you're not too overwhelmed. Please enjoy today's issue which <em>doesn't </em>talk about what's new this year 😁</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Sponsor of the week - Bitrise</strong><br><br>Last year Bitrise launched Mobile DevOps Assessment survey to the mobile app developer world. The results are in!<br>You can find answers to popular questions like ‘what percentage of teams use code generation tools’. Download the report to receive the results, as well as lots of free resources on Mobile DevOps!<br><br><strong><a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Download free report</a></strong></div></div><h2 id="happy-wwdc">Happy WWDC!</h2><p>I will share my favorites from WWDC 2023 at a later point - but for now, here are notable things available from iOS 15 that are a must for modern UIKit apps 😋</p><figure class="kg-card kg-image-card"><a href="https://twitter.com/jamesdempsey/status/1666068476883259397?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-09-12.22.21.png" class="kg-image" alt loading="lazy" width="1226" height="622" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/06/Xnapper-2023-06-09-12.22.21.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/06/Xnapper-2023-06-09-12.22.21.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/Xnapper-2023-06-09-12.22.21.png 1226w" sizes="(min-width: 720px) 720px"></a></figure><h3 id="bar-appearance">Bar appearance</h3><p>Definition-based configuration for different states of the UINavigationBar: <code><a href="https://developer.apple.com/documentation/uikit/uinavigationbar/3198028-standardappearance?ref=ioscodereview.com">standardAppearance</a></code>, <code><a href="https://developer.apple.com/documentation/uikit/uinavigationbar/3198026-compactappearance?ref=ioscodereview.com">compactAppearance</a></code>,  <code><a href="https://developer.apple.com/documentation/uikit/uinavigationbar/3198027-scrolledgeappearance?ref=ioscodereview.com">scrollEdgeAppearance</a></code>, <code><a href="https://developer.apple.com/documentation/uikit/uinavigationbar/3750865-compactscrolledgeappearance?ref=ioscodereview.com">compactScrollEdgeAppearance</a></code>. And there's a similar comnfiguration available for <code><a href="https://developer.apple.com/documentation/uikit/uitabbar/3198046-standardappearance?ref=ioscodereview.com">UITabbBar</a></code> 🙂</p><h3 id="uibutton-styling">UIButton styling</h3><p>Definition-based configuring of the UIButtons, so making a capsule button is almost as easy as in SwiftUI using <a href="https://developer.apple.com/documentation/uikit/uibutton/configuration?ref=ioscodereview.com"><code>UIButton.Configuration</code></a>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/image-1.png" class="kg-image" alt loading="lazy" width="780" height="600" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/06/image-1.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/image-1.png 780w" sizes="(min-width: 720px) 720px"><figcaption>https://useyourloaf.com/blog/button-configuration-in-ios-15/</figcaption></figure><h3 id="no-cell-subclassing">No cell subclassing</h3><p>It's not necessary anymore to subclass system cells - <code><a href="https://developer.apple.com/documentation/uikit/uitableviewcell/3750915-configurationupdatehandler?ref=ioscodereview.com">configurationUpdateHandler</a></code> lets us hook into state updates and update the cell's appearance. This fits well with the <code><a href="https://developer.apple.com/documentation/uikit/uitableviewcell/3601057-contentconfiguration?ref=ioscodereview.com">contentConfiguration</a></code> and <code><a href="https://developer.apple.com/documentation/uikit/uitableviewcell/3601055-backgroundconfiguration?ref=ioscodereview.com">backgroundConfiguration</a></code> of the cell - which again, make configuring cells as declarative as it can get in UIKit 😋 And of course, this is available for both UITableView and UICollectionView. </p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/image.png" class="kg-image" alt loading="lazy" width="1198" height="350" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/06/image.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/06/image.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/06/image.png 1198w" sizes="(min-width: 720px) 720px"></figure><p>If we need to make a custom-designed cell, then we can dive into <em>content views</em> - a new way to provide the custom content for the cell. A content view works with a <code>contentConfiguration</code> - and again, it doesn't require subclassing of UITableViewCell/UICollectionViewCell. To learn about it, you can follow Apple's official interactive tutorial:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/tutorials/app-dev-training/using-content-views?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Using content views | Apple Developer Documentation</div><div class="kg-bookmark-description">In this tutorial, you’ll add capabilities to the app’s editing mode that transform a view-only list of reminder details into editable controls.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><h2 id="structural-identity-in-swiftui">Structural identity in SwiftUI</h2><p>Structural identity is how SwiftUI understands your view hierarchy and recognizes particular views without specific identifiers. It is crucial to understand how it works to build great and performant views with SwiftUI:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftwithmajid.com/2021/12/09/structural-identity-in-swiftui/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Structural identity in SwiftUI</div><div class="kg-bookmark-description">Structural identity is the type of identity that SwiftUI uses to understand your views without an explicit identifier by using your layout description. This week we will learn how to improve performance and eliminate unwanted animations by using inert view modifiers in SwiftUI.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftwithmajid.com/public/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Majid</span><span class="kg-bookmark-publisher">Majid Jabrayilov</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftwithmajid.com/public/swiftui.png" alt=""></div></a></figure><h2 id="and-more">And more... </h2><p>For some less technical reading, my husband David has started a blog where he writes about the tech industry. He's been supporting me throughout my carreer journey, and I can only return the favour 🙂 If you're curious to read about the challenges of running a startup, or how we can fix the state of hiring, check out his writing:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@davidbbn/the-flawed-dance-of-recruitment-breaking-the-cycle-for-a-better-hiring-process-bab7c30a263c?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Flawed Dance of Recruitment: Breaking the Cycle for a Better Hiring Process</div><div class="kg-bookmark-description">Introduction</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">David Babayan</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/0*0wonEGM9ooxkxDPQ" alt=""></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/@davidbbn/the-silent-killer-of-startups-how-a-lack-of-inspiration-destroys-your-team-and-business-73c7f7c3e987?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Silent Killer of Startups: How a Lack of Inspiration Destroys Your Team and Business</div><div class="kg-bookmark-description">In this post, I summarise a decade of my experience, analyse problems that I encountered in every company I worked with and…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Medium</span><span class="kg-bookmark-publisher">David Babayan</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/0*1g23PHOj8bOCwLaN" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! <br>Thank you to <a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Bitrise</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #49 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 49th issue of iOS Code Review! I hope you enjoy reading through today&#39;s collection 💌

Setapp offers a collection of 240+ trustworthy, advanced paid apps under one subscription. It takes away the pain of looking up, comparing, buying, and managing separate apps.

Try Setapp ]]></description>
        <link>https://ioscodereview.com/issues/49/</link>
        <guid isPermaLink="false">646f64281003b40001340e23</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 25 May 2023 08:05:24 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 49th issue of iOS Code Review! I hope you enjoy reading through today's collection 💌</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>Setapp</strong> offers a collection of 240+ trustworthy, advanced paid apps under one subscription. It takes away the pain of looking up, comparing, buying, and managing separate apps.<br><br><a href="https://setapp.sjv.io/c/4300314/343321/5114?ref=ioscodereview.com"><strong>Try Setapp for free</strong></a></div></div><h2 id="the-efficiency-of">The efficiency of +=</h2><p>The <code>+=</code> operator, when performed a non-trivial number times, is much faster than addition and assignment with <code>+</code>.  <em>(the Twitter integration is temporarily out of commission, click on the image to read the thread)</em></p><figure class="kg-card kg-image-card"><a href="https://twitter.com/cpatrascudev/status/1661340099190161409?ref=ioscodereview.com"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/05/Xnapper-2023-05-25-16.24.29.png" class="kg-image" alt loading="lazy" width="1206" height="1530" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/05/Xnapper-2023-05-25-16.24.29.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/05/Xnapper-2023-05-25-16.24.29.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/05/Xnapper-2023-05-25-16.24.29.png 1206w" sizes="(min-width: 720px) 720px"></a></figure><h2 id="ranged-line-limit-in-swiftui">Ranged line limit in SwiftUI</h2><p>We can specify a number of lines as a range, and SwiftUI will reserve space for the lower bound - even if the text itself takes less space (available from iOS 16)</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mastodon.social/@ramzesenok/110420635568400311?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Roman (@ramzesenok@mastodon.social)</div><div class="kg-bookmark-description">Attached: 1 image - Day 21Setting line limit in #SwiftUI means setting its upper limit. Text will render as many lines as needed for content but no more that the limit. But we can also set a range as a limit. Now it will reserve space for the lower bound and render no more than upper bound lines</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mastodon.social/packs/media/icons/apple-touch-icon-1024x1024-db6849588b44f525363c37b65ef0ac66.png" alt=""><span class="kg-bookmark-author">Mastodon</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://files.mastodon.social/media_attachments/files/110/420/634/425/707/478/original/d3a83bfbee012586.jpeg" alt=""></div></a></figure><h2 id="accessibility-for-custom-swiftui-views">Accessibility for custom SwiftUI views</h2><p>Whenever we make a fancy custom control in SwiftUI, we don't have to spend time making it accessible by itself - instead we can use the <code>.accessibilityRepresentation</code> modifier. Whenever VoiceOver navigation is used, SwiftUI will use the view created by this closure instead of our custom view. By using a system control in this representation, we save on effort while users will be happier 🤩</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mastodon.social/@ramzesenok/110394467783618299?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Roman (@ramzesenok@mastodon.social)</div><div class="kg-bookmark-description">Attached: 1 image - Day 16Sometimes we come up with crazy fancy controls that are very inaccessible. We can try making it accessible here and there or we can also replace them with something very simple yet completely accessible. Here comes &#x60;accessibilityRepresentation&#x60; in play</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mastodon.social/packs/media/icons/apple-touch-icon-1024x1024-db6849588b44f525363c37b65ef0ac66.png" alt=""><span class="kg-bookmark-author">Mastodon</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://files.mastodon.social/media_attachments/files/110/394/466/971/022/173/original/10dbb1c46a040055.jpeg" alt=""></div></a></figure><h2 id="custom-scopes-in-swift">Custom scopes in Swift </h2><p>I love this trick and use it quite a lot. Every set of curly braces is a scope - meaning that variables declared inside it are not available on the outside. Naturally, functions, closures, and if statements are scopes, but no one is stopping us from creating scopes whenever we want - the easiest way to do that is with a <code>do {}</code> syntax. <br>Why, you ask? This allows to isolate some intricate logic, when you don't want to move out a piece of code to a separate function, but still want some extra separation inside the funciton. Last time I used it for calculating frames inside <code>layoutSubviews</code>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mastodon.social/@ramzesenok/110377223702997882?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Roman (@ramzesenok@mastodon.social)</div><div class="kg-bookmark-description">Attached: 1 image - Day 13Ever wanted to somehow scope a portion of logic from the rest? You can use &#x60;do {}&#x60; for that. Scoping can help you limit lifetime and visibility of some variables resulting in cleaner code and faster app</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mastodon.social/packs/media/icons/apple-touch-icon-1024x1024-db6849588b44f525363c37b65ef0ac66.png" alt=""><span class="kg-bookmark-author">Mastodon</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://files.mastodon.social/media_attachments/files/110/377/222/515/737/038/original/da0b2cc848ea416c.jpeg" alt=""></div></a></figure><h2 id="the-importance-of-code-ownership">The importance of code ownership</h2><p>Most of important and successful projects, even though they started off small, go through different phases that turn a proud shiny code into a piece of cryptic code everyone fears and despises.<br>In this article you'll read about how and why it happens, and find recommendations on making sure the code is properly owned - and thus maintained.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://betterprogramming.pub/the-underestimated-importance-of-clear-code-ownership-baed758e47b8?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Importance of Code Ownership</div><div class="kg-bookmark-description">Well-owned code is well-maintained code</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Better Programming</span><span class="kg-bookmark-publisher">Elye</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/0*H3S_YK6nECBOfe-3" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! <br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!<br><br><em>* this issue contains an affiliate link to <a href="https://setapp.sjv.io/c/4300314/343321/5114?ref=ioscodereview.com">Setapp</a></em></p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #48 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 48th issue! Today you&#39;ll learn about initializing views, sorting arrays of strings, modern UISegmentedControl, and setting up git-ignore for your project. Enjoy! 🌞

💎 Sponsor of the week - Bitrise

What happens when you survey 1600+ Mobile DevOps teams? You get 5 key Mobile DevOps ]]></description>
        <link>https://ioscodereview.com/issues/48/</link>
        <guid isPermaLink="false">645cd5d06b2acc000131225f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 11 May 2023 05:53:06 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 48th issue! Today you'll learn about initializing views, sorting arrays of strings, modern <code>UISegmentedControl</code>, and setting up git-ignore for your project. Enjoy! 🌞</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Sponsor of the week - Bitrise</strong><br><br>What happens when you survey 1600+ Mobile DevOps teams? You get 5 key Mobile DevOps benchmarks that can guide mobile teams to high performance. Download our free report and start setting goals for your team based on industry-recognized benchmarks.<br><br><strong><a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Download free report</a></strong></div></div><h2 id="lightweight-view-initialization">Lightweight view initialization</h2><p>Initializer of a SwiftUI view should be as lightweight as possible, as it is executed many times. In fact, it's a good rule of thumb for <code>UIView</code> and <code>UIViewController</code> initializers too - keep the heavier work for the moment when the view loads or appears. </p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Don&#39;t perform performance intensive operations in the initializer of the view. The initializer is called again when the count is incremented. If you pass count to the GreetView init then GreetView body is called and evaluated.<a href="https://twitter.com/hashtag/SwiftUI?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#SwiftUI</a> <a href="https://t.co/WQ0NwpXAY5?ref=ioscodereview.com">pic.twitter.com/WQ0NwpXAY5</a></p>&mdash; Mohammad Azam (@azamsharp) <a href="https://twitter.com/azamsharp/status/1656492297251434496?ref_src=twsrc%5Etfw&ref=ioscodereview.com">May 11, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="sorting-user-entered-strings">Sorting user-entered strings</h2><p>Don't just use <code>.sorted()</code> on arrays of strings. A quote from <code><a href="https://developer.apple.com/documentation/foundation/nsstring/1409742-localizedstandardcompare?ref=ioscodereview.com">localizedStandardCompare(_:)</a></code> documentation:</p><blockquote>This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.</blockquote><p>By the way, Swift's String implementation is so great, that it already treats special characters correctly during equality checks with <code>==</code>. Using the right comparing method brings the same greatness to sorting of strings 🙌 <br><br>An example from <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/stringsandcharacters/?ref=ioscodereview.com">the Swift docs</a> about equality with diatrics:</p><blockquote>The letter <code>é</code> can be represented as the single Unicode scalar <code>é</code> (<code>LATIN SMALL LETTER E WITH ACUTE</code>, or <code>U+00E9</code>). However, the same letter can also be represented as a <em><em>pair</em></em> of scalars — a standard letter <code>e</code> (<code>LATIN SMALL LETTER E</code>, or <code>U+0065</code>), followed by the <code>COMBINING ACUTE ACCENT</code>scalar (<code>U+0301</code>). The <code>COMBINING ACUTE ACCENT</code> scalar is graphically applied to the scalar that precedes it, turning an <code>e</code> into an <code>é</code> when it’s rendered by a Unicode-aware text-rendering system.<br><br>... Two <code>String</code> values (or two <code>Character</code> values) are considered equal if their extended grapheme clusters are <em><em>canonically equivalent</em></em>.<br><br>... <code>LATIN SMALL LETTER E WITH ACUTE</code> (<code>U+00E9</code>) is canonically equivalent to <code>LATIN SMALL LETTER E</code> (<code>U+0065</code>) followed by <code>COMBINING ACUTE ACCENT</code> (<code>U+0301</code>). Both of these extended grapheme clusters are valid ways to represent the character <code>é</code>, and so they’re considered to be canonically equivalent</blockquote><p>Read the article from the tweet to learn about more ways of sorting arrays of strings.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">You should use localizedStandardCompare when working with text that&#39;s presented to the user.<a href="https://t.co/DPlRXmO41e?ref=ioscodereview.com">https://t.co/DPlRXmO41e</a> <a href="https://t.co/eF5UKGeEQ5?ref=ioscodereview.com">pic.twitter.com/eF5UKGeEQ5</a></p>&mdash; Sarun W. (@sarunw) <a href="https://twitter.com/sarunw/status/1620874281059028997?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 1, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="modern-uisegmentedcontrol">Modern UISegmentedControl </h2><p>Lovely modern API for reacting to <code>UISegmentedControl</code> selection, that doesn't require <code>@objc</code> methods anymore:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">It appears that Apple has made UISegmentedControl configurable using UIAction, similar to how they did it for UIButton. 👍🏻<a href="https://twitter.com/hashtag/iosdev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdev</a> <a href="https://t.co/nzOiH2nB40?ref=ioscodereview.com">pic.twitter.com/nzOiH2nB40</a></p>&mdash; Lee Kah Seng (@Lee_Kah_Seng) <a href="https://twitter.com/Lee_Kah_Seng/status/1646116887175266304?ref_src=twsrc%5Etfw&ref=ioscodereview.com">April 12, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="avoiding-junk-in-the-git-diff">Avoiding junk in the git diff </h2><p>Inside each <code>.xcodeproj</code> and <code>.xcworkspace</code> file there is a folder called <code>xcuserdata</code>, containing files that are individual to each user who opens the project - that users breakpoints, saved search scopes, and other configurations. <code>xcshareddata</code> folder contains files belonging to the whole project such as schemes and the <code>Package.resolved</code> file.<br>💡 <code> xcuserdata</code> folder should be git-ignored, to avoid polluting the git tree and commit history, especially on projects with many contributors.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/05/xcuserdata.png" class="kg-image" alt loading="lazy" width="656" height="669" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/05/xcuserdata.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/05/xcuserdata.png 656w"></figure><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I hereby vow to start every new Xcode project with<br><br>&quot;touch .gitignore &amp;&amp; echo &quot;*.xcuserstate&quot; &gt;&gt; .gitignore&quot;<br><br>Maybe there&#39;s a way to automate that when initialising a git repo?</p>&mdash; Johan Forsell (@joforselldev) <a href="https://twitter.com/joforselldev/status/1600598788753788945?ref_src=twsrc%5Etfw&ref=ioscodereview.com">December 7, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Yes, if you create your repo on GitHub, you can actually select this .gitignore file in a dropdown (or just copy it manually):<a href="https://t.co/lLz3dXdGgj?ref=ioscodereview.com">https://t.co/lLz3dXdGgj</a></p>&mdash; Cihat Gündüz (@Jeehut) <a href="https://twitter.com/Jeehut/status/1600730139725541379?ref_src=twsrc%5Etfw&ref=ioscodereview.com">December 8, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p></p><p>✌️<br>Alright, that's it for today! <br>Thank you to <a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Bitrise</a> for sponsoring this issue ❤️<br>I'm curious if you found any of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #47 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 47th issue of iOS Code Review! I hope you enjoy today&#39;s collection 🌞

💎 Sponsor of the week - Bitrise

What happens when you survey 1600+ Mobile DevOps teams? You get 5 key Mobile DevOps benchmarks that can guide mobile teams to high performance. Download ]]></description>
        <link>https://ioscodereview.com/issues/47/</link>
        <guid isPermaLink="false">644aa19ea581e7003d5c18f7</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Fri, 28 Apr 2023 03:30:39 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 47th issue of iOS Code Review! I hope you enjoy today's collection 🌞</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Sponsor of the week - Bitrise</strong><br><br>What happens when you survey 1600+ Mobile DevOps teams? You get 5 key Mobile DevOps benchmarks that can guide mobile teams to high performance. Download our free report and start setting goals for your team based on industry-recognized benchmarks.<br><br><strong><a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Download free report</a></strong></div></div><h2 id="use-the-right-assertions">Use the right assertions</h2><p>Swift offers a number of ways to assert, i.e. stop the program, when something unexpected happens. Here's the gist of what to use when:</p><ul><li>Use <code>assert()</code> as often as you want, because it lets you check things are how you expect without having a performance impact in release mode, where the check is ignored</li><li>Use the unconditional <code>assertionFailure()</code> if there’s somewhere your code shouldn’t reach, but it’s not a disaster if it happens.</li><li>Use <code>precondition()</code> only when a check is critical to keep your user safe (app will crash). Same goes for <code>fatalError()</code>.</li></ul><p>Related, Combine's <code><a href="https://developer.apple.com/documentation/combine/fail/breakpointonerror()?ref=ioscodereview.com">breakpointOnError()</a></code> acts as a precondition and will stop (crash) the app in release builds too:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">TIL not to use Combine&#39;s breakpointOnError() in production builds.<br>It crashes the app when not attached to a debugger 😬</p>&mdash; Marina Gornostaeva ✨ (@hybridcattt) <a href="https://twitter.com/hybridcattt/status/1437767688672133128?ref_src=twsrc%5Etfw&ref=ioscodereview.com">September 14, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Read more on Hacking with Swift:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.hackingwithswift.com/plus/intermediate-swift/understanding-assertions?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Understanding assertions – Hacking with Swift+</div><div class="kg-bookmark-description">Assertions allow us to have Swift silently check the state of our program at runtime, but if you want to get them right you need to understand some intricacies. In this article I’ll walk you through the five ways we can make assertions in Swift, and provide clear advice on which to use and when.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.hackingwithswift.com/android-icon-192x192.png" alt=""><span class="kg-bookmark-author">Hacking with Swift</span><span class="kg-bookmark-publisher">Paul Hudson twostraws</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.hackingwithswift.com/img/thumbnails/vimeo-442522819.jpg" alt=""></div></a></figure><h2 id="private-set">Private Set</h2><p>Don't know who needs to hear this but here's a reminder that <code>private(set)</code> exists 🙂</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">TIL you can write `public private(set) var` or even `public internal(set) var` in <a href="https://twitter.com/hashtag/swiftlang?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#swiftlang</a> for public get and private/internal set. I used to write a regular _property and a public computed property for that 😅</p>&mdash; Pavel (@rl_pavel) <a href="https://twitter.com/rl_pavel/status/1538334281440837637?ref_src=twsrc%5Etfw&ref=ioscodereview.com">June 19, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="implementing-reachability">Implementing reachability</h2><p>The users won’t always have a good internet connection, so optimizing your app for bad networking conditions is essential. <br>Apple directly advises against checking for connection state, and recommends attempting to make a network call either way, and respond to a failure. <br>When you really need to know the state of the connection, use <a href="https://developer.apple.com/documentation/network/nwpathmonitor?ref=ioscodereview.com"><code>NWPathMonitor</code></a> to observe conenctivity. It's available since iOS 12, so there's no need for a third party reachability library anymore.<br>Antoine covers more details in his new article:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.avanderlee.com/swift/optimizing-network-reachability/?ref=ioscodereview.com#responding-to-networking-errors"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Optimizing your app for Network Reachability</div><div class="kg-bookmark-description">Optimize your app for Networking Connectivity and prevent common mistakes like pre-checking for reachability.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.avanderlee.com/wp-content/uploads/fbrfg/apple-touch-icon.png?v&#x3D;2" alt=""><span class="kg-bookmark-author">SwiftLee</span><span class="kg-bookmark-publisher">Antoine van der Lee</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://swiftlee-banners.herokuapp.com/imagegenerator.php?title&#x3D;Optimizing+your+app+for+Network+Reachability" alt=""></div></a></figure><h2 id="available-attribute">@available attribute</h2><p>My favorite use for the <code>@available</code> attribute is marking <code>initWithCoder:</code> methods, so they don't come up in autocomplete for the class:</p><pre><code class="language-swift">final class MyView: UIView {

  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  init(customStuff: [Int]) {...}
}</code></pre><p>There are other handy uses, such as marking your methods as deprecated - we don't have to provide the iOS version, and can just mark the method as "undesireable" for use:</p><pre><code class="language-swift">@available(*, deprecated, message: "Use TheNewImplementation instead. OldImplementation will be deleted soon.")
class OldImplementation { ... }</code></pre><p>Here's a short handy list of possible parameters to the <code>@available</code> attribite:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://tanaschita.com/20230206-the-available-attribute-in-ios/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to use the @available attribute in Swift</div><div class="kg-bookmark-description">Swift provides the @available attribute which we can use to make our code only available for certain Swift language versions or platforms. Learn about the arguments unavailable, introduced, deprecated, obsoleted and more.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://tanaschita.com/favicon.ico" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://tanaschita.com/og/20230206-the-available-attribute-in-ios.png" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! <br>Thank you to <a href="https://yo.bitrise.io/mobile-devops-assessment-report-2023-download.html?utm_source=sponsorships-newsletter&utm_campaign=MODAS_campaign_2023&utm_content=isocodereviewQ2">Bitrise</a> for sponsoring this issue ❤️<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #46 ]]></title>
        <description><![CDATA[ Hi there,
welcome to the 46th issue of the newsletter! Today among other things I&#39;m summarizing the updates in Xcode and Swift that affect code and project quality. Hope you enjoy the reading 😊


Iterating over some elements

Here&#39;s how to iterate over only some elements in ]]></description>
        <link>https://ioscodereview.com/issues/46/</link>
        <guid isPermaLink="false">6437d17e4998d5003d511aa1</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 13 Apr 2023 04:37:25 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, <br>welcome to the 46th issue of the newsletter! Today among other things I'm summarizing the updates in Xcode and Swift that affect code and project quality. Hope you enjoy the reading 😊</p><h2 id="iterating-over-some-elements">Iterating over some elements</h2><p>Here's how to iterate over only some elements in the array. Both options, for-case-let and for-in-if, are more efficient than filtering the array and iterating on the filtered results 🙌</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Swift has a `for-case-let` syntax, which is equivalent to the `for-in...if-let` syntax. The former makes code cleaner but less expressive.<br>Personally, I would prefer to use the latter syntax to keep my code expressive. I wonder how commonly the `for-case-let` syntax is used. 🤔 <a href="https://t.co/Fngk9h4e40?ref=ioscodereview.com">pic.twitter.com/Fngk9h4e40</a></p>&mdash; Lee Kah Seng (@Lee_Kah_Seng) <a href="https://twitter.com/Lee_Kah_Seng/status/1640950212482019328?ref_src=twsrc%5Etfw&ref=ioscodereview.com">March 29, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="xcode-143-swift-58">Xcode 14.3 &amp; Swift 5.8</h2><p>There's a bunch of improvements available in the new Swift and Xcode. Here are a few things that caught my attention: </p><h3 id="implicit-self">Implicit self</h3><ul><li>Implicit <code>self</code> is now permitted for <code>weak self</code> captures, after <code>self</code> is unwrapped:</li></ul><pre><code class="language-swift">class ViewController {
  let button: Button

  func setup() {
      button.tapHandler = { [weak self] in
          guard let self else { return }
          dismiss() // refers to `self.dismiss()`
      }
  }

  func dismiss() { ... }
}</code></pre><h3 id="debugging-previews-with-print">Debugging previews with print</h3><ul><li><code>print</code> output now appears in the console for SwiftUI Previews by selecting “Preview” tab in the console.</li></ul><h3 id="previews-in-modular-dependencies">Previews in modular dependencies</h3><ul><li>Fixed: Previews can fail when previewing a file inside of a Swift package target that is the dependency of an executable target. </li></ul><h3 id="waiting-for-expectations">Waiting for expectations</h3><ul><li>The <code>timeout</code> argument of <code>XCTestCase.wait(for:timeout:enforceOrder:)</code> and related methods is now optional—if you don’t specify it, the function waits indefinitely (until the overall test times out.) To ensure reasonable execution time, set an appropriate value for the <code>executionTimeAllowance</code> property of the running <code>XCTestCase</code> instance (<code>self</code>).</li><li><code>XCTestCase.wait(for:timeout:enforceOrder:)</code> and related methods are now marked unavailable in concurrent Swift functions because they can cause a test to deadlock. Instead, you can use the new concurrency-safe <code>XCTestCase.fulfillment(of:timeout:enforceOrder:)</code> method.</li></ul><h3 id="test-plans">Test plans</h3><ul><li>Xcode now defaults to using a test plan for new projects. Learn more about test plans in the documentation: <a href="https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback?changes=_8&ref=ioscodereview.com">Improving code assessment by organizing tests into test plans</a> </li></ul><p><br>Read about everything new here (this links directly to the section about Swift but you can scroll up and down to read about all the changes in Xcode): </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://developer.apple.com/documentation/xcode-release-notes/xcode-14_3-release-notes?ref=ioscodereview.com#Swift"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Xcode 14.3 Release Notes | Apple Developer Documentation</div><div class="kg-bookmark-description">Update your apps to use new features, and test your apps against API changes.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://developer.apple.com/apple-logo.svg" alt=""><span class="kg-bookmark-author">Apple Developer Documentation</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.developer.apple.com/tutorials/developer-og.jpg" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today.<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #45 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 45th issue of iOS Code Review!
I hope you enjoy the reading below 🌞

💎 Supporter of the week - RevenueCat 💎

In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it simple by providing a backend and a wrapper ]]></description>
        <link>https://ioscodereview.com/issues/45/</link>
        <guid isPermaLink="false">6413135c0ed503003db67ea5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 16 Mar 2023 06:58:41 -0700</pubDate>
        <media:content url="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/03/ios-code-review-newsletter-header-4.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 45th issue of iOS Code Review! <br>I hope you enjoy the reading below 🌞</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Supporter of the week - RevenueCat 💎</strong><br><br>In-app subscriptions are a pain to implement, hard to test, and full of edge cases. <strong>RevenueCat</strong> makes it simple by providing a backend and a wrapper around Apple's StoreKit and Google Play Billing. Get started for free.<br><br><a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter"><strong>Learn more</strong></a></div></div><h2 id="modern-uibutton-actions">Modern UIButton actions</h2><p>With iOS 17 on the doorstep (yes, it's 3 months until WWDC), most projects have upgraded to newer minimum deployment targets. So it's a perfect time to remind about this lovely <code>UIAction</code> API for adding handlers to <code>UIButton</code>s - where we don't need to involve @objc #selectors anymore 🎉</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">In case you are not aware, there is a more Swifty way to add an action to buttons in Swift since iOS 14.<a href="https://twitter.com/hashtag/iosdev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdev</a> <a href="https://t.co/WS5RpAkwlh?ref=ioscodereview.com">pic.twitter.com/WS5RpAkwlh</a></p>&mdash; Lee Kah Seng (@Lee_Kah_Seng) <a href="https://twitter.com/Lee_Kah_Seng/status/1632998136158498816?ref_src=twsrc%5Etfw&ref=ioscodereview.com">March 7, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="inline-images-in-text-in-swiftui">Inline images in Text in SwiftUI</h2><p>There's a lightweight way to insert images inside <code>Text</code> in SwiftUI - in string interpolation. If it's a custom image, it will be displayed in the original size. But if the image is an SF symbol, it will take on view modifiers applied to the <code>Text</code> - font, symbol variants, color, etc.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">SwiftUI supports inline image with string interpolation in iOS 14.<a href="https://t.co/4aAqOS4ULI?ref=ioscodereview.com">https://t.co/4aAqOS4ULI</a><a href="https://twitter.com/hashtag/iosdev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdev</a> <a href="https://twitter.com/hashtag/swiftui?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#swiftui</a> <a href="https://t.co/0Gel0DE095?ref=ioscodereview.com">pic.twitter.com/0Gel0DE095</a></p>&mdash; Sarun W. (@sarunw) <a href="https://twitter.com/sarunw/status/1633916637752750080?ref_src=twsrc%5Etfw&ref=ioscodereview.com">March 9, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="deciphering-core-data-error-codes">Deciphering Core Data error codes </h2><p>CoreData produces nondescriptive errors such as  <code>Domain=NSCocoaErrorDomain Code=1610 "The operation couldn't be completed. (Cocoa error 1610.)</code> . There's a way to quickly check the meaning of the error code - by opening <code>CoreDataErrors.h</code> with Quick Open (just make sure to open the original and not the Swift interface). Alternatively, it's available online: <a href="https://gist.github.com/hishma/7cb505f94230ac7d7ed53d52a1e6dab6?ref=ioscodereview.com">CoreDataErrors.h as a gist on GitHub</a></p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">TIL that you can navigate to a file called `CoreDataErrors.h` in any iOS project where you can find all the obscure CoreData error codes in an enum along with their definitions. Just Shift+Cmd+O inside Xcode and type `CoreDataErrors.h` then press Enter. <a href="https://twitter.com/hashtag/CoreData?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#CoreData</a> <a href="https://twitter.com/hashtag/iOS?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iOS</a> <a href="https://twitter.com/hashtag/Swift?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#Swift</a></p>&mdash; aly (@aliiyakan) <a href="https://twitter.com/aliiyakan/status/1131587587053957121?ref_src=twsrc%5Etfw&ref=ioscodereview.com">May 23, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="storyboards-vs-programmatic-layout">Storyboards vs programmatic layout</h2><p>When we talk about UIKit, programmatic layout has lots of benefits - easier code review, traceable changes via git, and code is a single-source-of-truth. But some teams prefer storyboards for their own reasons. In that case, here's an article with advice on how to improve quality of life when working with interface builder:</p><ul><li>understanding the XML structure</li><li>what issues to look for during code review</li><li>avoiding merge conflicts by locking against changes</li></ul><p><em>Note:</em> In the article the author mentions faster compilation time with storyboards vs programmatic layout. That can be true with lots and lots of layout code, but also the code structure itself affects compilation time, not only the amount of it. For example, if you use a global spacing constant, changing that one value can cause almost a full re-compile, while changing one storyboard file only recompiles that one file. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://medium.com/99dotco/why-did-we-change-our-ios-rule-to-allow-using-storyboard-45cb48d024?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why did we change our iOS rule to allow using Storyboard?</div><div class="kg-bookmark-description">Our UI creation rule was creating a UI programmatically. But recently, we changed it.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">99.co</span><span class="kg-bookmark-publisher">Sungwook (Shawn) Baek</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/v2/resize:fit:1200/1*ePqFvQNf3TEP7fEMA-S-jA.png" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter">RevenueCat</a> for sponsoring this issue ❤️<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #44 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to the 44th issue of iOS Code Review! Today I&#39;m sharing five topics that caught my attention during the past couple of weeks. Enjoy the reading!

💎 Supporter of the week - RevenueCat 💎

In-app subscriptions are a pain to implement, hard to test, and full of ]]></description>
        <link>https://ioscodereview.com/issues/44/</link>
        <guid isPermaLink="false">64008003f9eebe003df594ca</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 02 Mar 2023 04:48:03 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, <br>Welcome to the 44th issue of iOS Code Review! Today I'm sharing five topics that caught my attention during the past couple of weeks. Enjoy the reading!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Supporter of the week - RevenueCat 💎</strong><br><br>In-app subscriptions are a pain to implement, hard to test, and full of edge cases. <strong>RevenueCat</strong> makes it simple by providing a backend and a wrapper around Apple's StoreKit and Google Play Billing. Get started for free.<br><br><a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter">Learn more</a></div></div><h2 id="structuring-unit-tests">Structuring unit tests</h2><p>To prevent our complex unit tests from turning into a mush of hard-to-read code, we can annotate the tests using the Given-When-Then technique:</p><!--kg-card-begin: markdown--><pre><code>// Given
let mockStorage = Storage(value: &quot;123&quot;)
let sut = Cache(storage: mockStorage)
// When
sut.clear()
// Then
XCTAssertEqual(mockStorage.value, nil)
</code></pre>
<!--kg-card-end: markdown--><p>This is a tiny example, but a real saver for more complex test scenarios. <br>Read more by Martin Fowler:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://martinfowler.com/bliki/GivenWhenThen.html?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">bliki: GivenWhenThen</div><div class="kg-bookmark-description">a bliki entry for GivenWhenThen</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://martinfowler.com/favicon.ico" alt=""><span class="kg-bookmark-author">martinfowler.com</span><span class="kg-bookmark-publisher">Martin Fowler</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://martinfowler.com/logo-sq.png" alt=""></div></a></figure><h2 id="dont-change-default-params-when-subclassing">Don't change default params when subclassing</h2><p>This unexpected behavior came as a total surprise for me - when we override a method with default parameters, sometimes the default parameters of the superclass's method will be used. So we should keep the default values the same in the override's method signature to avoid surprises and bugs.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://betterprogramming.pub/an-unexpected-behavior-of-subclasses-e684b3267e30?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">An Unexpected Behavior of Subclasses in Swift</div><div class="kg-bookmark-description">Don’t change default param’s values when subclassing</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Better Programming</span><span class="kg-bookmark-publisher">Riccardo Cipolleschi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/max/1200/0*Oz6xtDUU5FQDlXvl" alt=""></div></a></figure><h2 id="delegate-naming-conventions">Delegate naming conventions</h2><p>The delegate pattern is familiar to iOS developers, but naming of the delegate methods can differ. A good practice is to include the sender parameter, and make it clear in the function name that it's a delegate method, so it stands out at the implementer side.<br>Read about good naming conventions for delegate methods by John Sundell:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://swiftbysundell.com/articles/delegation-in-swift/?ref=ioscodereview.com#protocols"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Delegation in Swift | Swift by Sundell</div><div class="kg-bookmark-description">The delegate pattern has long been very prominent on Apple’s platforms, and used for everything from handling table view events using UITableViewDelegate, to modifying cache behavior using NSCacheDelegate. This week, let’s take a look at a few ways to implement the delegate pattern, along with their…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://swiftbysundell.com/images/favicon.png" alt=""><span class="kg-bookmark-author">Swift by Sundell</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.swiftbysundell.com/images/social.png" alt=""></div></a></figure><h2 id="fixing-file-header-template-for-packages">Fixing file header template for packages</h2><p>Xcode still doesn't add proper filename, project name and copyright into new files created in SPM packages. Here's a short article explaining how to finally fix that:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://samwize.com/2023/02/28/xcode-header-template-for-swift-packages/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Xcode Header Template for Swift Packages</div><div class="kg-bookmark-description">If you use Swift Package, there are 2 pesky problems whenever you create a new file.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://samwize.com/images/favicon-180.png" alt=""><span class="kg-bookmark-author">@samwize</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://samwize.com/images/empty-swift-file-template.jpg" alt=""></div></a></figure><h2 id="learn-about-swiftui-view-lifecycle">Learn about SwiftUI view lifecycle</h2><p>The demo project you didn't know you needed :) </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/ole/swiftui-view-lifecycle?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - ole/swiftui-view-lifecycle: Observe how different SwiftUI container views affect state and lifecycle events (onAppear, onDisappear).</div><div class="kg-bookmark-description">Observe how different SwiftUI container views affect state and lifecycle events (onAppear, onDisappear). - GitHub - ole/swiftui-view-lifecycle: Observe how different SwiftUI container views affect…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">ole</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/e7002a6f8ca283b5dcbe282b41c2131df0d6abc170bd7500a537dced105c09c0/ole/swiftui-view-lifecycle" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter">RevenueCat</a> for sponsoring this issue ❤️<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #43 ]]></title>
        <description><![CDATA[ Hi there, welcome to the 43rd issue and happy valentines day 💌
Enjoy the reading!

💎 Sponsor of the week - RevenueCat 💎

In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it simple by providing a backend and a wrapper around Apple&#39;s ]]></description>
        <link>https://ioscodereview.com/issues/43/</link>
        <guid isPermaLink="false">63eb54ceb29b78003d8b5129</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Tue, 14 Feb 2023 04:18:23 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, welcome to the 43rd issue and happy valentines day 💌<br>Enjoy the reading!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Sponsor of the week - RevenueCat 💎</strong><br><br>In-app subscriptions are a pain to implement, hard to test, and full of edge cases. <strong>RevenueCat</strong> makes it simple by providing a backend and a wrapper around Apple's StoreKit and Google Play Billing. Get started for free.<br><br><a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter">Learn more</a></div></div><h2 id="documenting-hacks">Documenting hacks</h2><p>How often do you add dispatch.async as a way to fix a bug? Hopefully not often! The core of solving a bug without causing more bugs, is understanding the root cause and fixing <em>that</em>. <br>But sometimes, even though we find the root cause, there's no way to address it, so a hacky workaround is necessary. In that case, make sure to add a detailed comment next to the hack. For your colleagues and your future self!</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The only right way to add DispatchQueue.main.async to fix a bug - with a big fat comment on top 👇 <a href="https://t.co/EcXMNoi9pu?ref=ioscodereview.com">pic.twitter.com/EcXMNoi9pu</a></p>&mdash; Marina Gornostaeva ✨ (@hybridcattt) <a href="https://twitter.com/hybridcattt/status/1625072288755245058?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 13, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="two-ways-to-mock-in-tests">Two ways to mock in tests</h2><p>Here's Manuel describing two ways to implement a loading view model and its tests. One employs protocols for dependency injecion, and another uses closures. The same example code is used in both approaches, so you can easily compare and pick your favorite. Beautiful and concise articles, with links to GitHub included.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mdb1.github.io/2023-02-13-enhancing-testability-with-protocols/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Enhancing Testability with protocols</div><div class="kg-bookmark-description">In the last post we’ve discussed hot to enhance testability without using protocols. In this one, we will build something similar but using protocols instead. We will be using dependency injection to be able to inject the real objects in the app, and inject mock objects in the tests / previews. We w…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mdb1.github.io/favicon.ico" alt=""><span class="kg-bookmark-author">The Product Engineer</span><span class="kg-bookmark-publisher">Manuel Herrera</span></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mdb1.github.io/2023-02-03-enhancing-testability-without-protocols/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Enhancing Testability without protocols</div><div class="kg-bookmark-description">We have all used protocols to enhance testability in our apps, but that can become too verbose, and add extra layers of abstractions to the code. Here is a different approach, without using protocols, that can achieve the same results with way less code. Let’s say we have a screen with a button that…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mdb1.github.io/favicon.ico" alt=""><span class="kg-bookmark-author">The Product Engineer</span><span class="kg-bookmark-publisher">Manuel Herrera</span></div></div></a></figure><h2 id="dont-subclass-urlcache">Don't subclass URLCache</h2><p>Few days ago I saw a post by Nikita on Mastodon asking if anyone could help him solve a bug with his <code>URLCache</code> subclass not actually caching anything. Some days later, he wrote a post with his findings. <br>Turns out, nowadays <code>URLCache</code> is not subclassable anymore, even though the documentation states that it is. Instead, we should build our custom caching logic above the url loading layer. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://zhuk.fi/subclassing-urlcache/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">A path of pain with URLCache eviction and subclassing</div><div class="kg-bookmark-description">URLCache class implements the caching of responses to URL load requests, by mapping NSURLRequest objects to CachedURLResponse objects. It provides a composite in-memory and on-disk cache, and lets you manipulate the sizes of both the in-memory and on-disk portions. You can also control the path wher…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://zhuk.fi/content/images/size/w256h256/2022/05/icon.png" alt=""><span class="kg-bookmark-author">Zhuk Notes</span><span class="kg-bookmark-publisher">Nikita Zhuk</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://zhuk.fi/content/images/2022/05/mountains-bg-1.jpeg" alt=""></div></a></figure><h2 id="whats-new-in-swifta-refresher">What's new in Swift - a refresher</h2><p>Sometimes when new stuff is released in Swift or the SDK, it gets forgotten because you can't use it right away. Swift versions is one of those things - they are released even before Xcode is.<br>So here's a refresher on the lovely Swift features we can now introduce in our projects on Xcode 14+ - the shorthand <code>if let</code>, new regex syntax, and more. Available in video and article format:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftwithvincent.com/blog/discover-some-new-features-of-swift-5-7?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Discover some New Features of Swift 5.7 — Swift with Vincent</div><div class="kg-bookmark-description">You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://images.squarespace-cdn.com/content/v1/63139bb1e1a1a078e071f30c/bd40c4d4-dc8b-48b7-a0cc-2209de7d1ab6/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Vincent</span><span class="kg-bookmark-publisher">Vincent Pradeilles</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://static1.squarespace.com/static/63139bb1e1a1a078e071f30c/63139c36429a5c059fca0020/6365055972188b0435e4e726/1667674177137/Swift-5.7.png?format&#x3D;1500w" alt=""></div></a></figure><h2 id="merge-when-ready-on-github">Merge when ready on GitHub</h2><p>Are you working in a repo where you have to wait for CI to finish before merging a pull request? Then GitHub's new merge queues feature is going to improve your day-to-day :)</p><blockquote>Before merge queues, developers were often required to update their pull request branches prior to merging to ensure their changes wouldn't break the main branch when merged. Each update resulted in a fresh round of continuous integration (CI) checks that would have to finish before the developer could attempt to merge. If another pull request got merged, every developer would have to go through the process again.</blockquote><p>Even if you're not needing the queue part, the "Merge when ready" button is the feature I've been missing all along.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.blog/changelog/2023-02-08-pull-request-merge-queue-public-beta/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Pull request merge queue (public beta) | GitHub Changelog</div><div class="kg-bookmark-description">Pull request merge queue (public beta)</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit&#x3D;192%2C192" alt=""><span class="kg-bookmark-author">The GitHub Blog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://user-images.githubusercontent.com/2503052/217027654-f570fb25-092d-476e-b6f5-0b31b8514662.png" alt=""></div></a></figure><p></p><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://www.revenuecat.com/?utm_source=ios_code_review&utm_medium=paid&utm_campaign=newsletter">RevenueCat</a> for sponsoring this issue ❤️<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #42 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to the 42nd issue, the answer to life and everything! This time, among other topics, there&#39;s a couple of tips about code and project setup improvements that facilitate speed - faster app launch, execution speed, and build times. Enjoy!

By the way, next issue will ]]></description>
        <link>https://ioscodereview.com/issues/42/</link>
        <guid isPermaLink="false">63dbb520181fc4003dc994da</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 02 Feb 2023 06:07:19 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, <br>Welcome to the 42nd issue, the answer to life and everything! This time, among other topics, there's a couple of tips about code and project setup improvements that facilitate speed - faster app launch, execution speed, and build times. Enjoy!</p><p>By the way, next issue will arrive on Tuesday, February 14th 💌</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Supporter of the week - Paste 💎</strong><br><br><strong>Paste</strong> is like a time machine for your clipboard. It brings all your copied items together in one place and makes it super easy to find your snippets with visual previews and powerful search. <br><br>It’s a go-to tool for thousands of developers who aim to speed up their daily workflow on the Mac. <br><br>Try <strong>Paste</strong> for free at 👉 <strong><a href="https://pasteapp.io/?ref=ioscodereview">pasteapp.io</a> </strong><br>they’re also <a href="https://pasteapp.notion.site/Join-Paste-Team-0499145c46fa46258d873bdb4ba05213?ref=ioscodereview.com">hiring macOS/iOS developers</a> ☺️</div></div><h2 id="speeding-app-launch-by-improving-code">Speeding app launch by improving code</h2><p>A story about DoorDash improving their app launch time by auditing and improving code that's run during startup. Among other things, I was surprised how small changes make a big difference. For example, shifting from using <code>String(describing:)</code> to <code>ObjectIdentifier</code> boosted their launch time by 11%! </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://doordash.engineering/2023/01/31/how-we-reduced-our-ios-app-launch-time-by-60/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How We Reduced Our iOS App Launch Time by 60%</div><div class="kg-bookmark-description">Learn how DoorDash went about optimizing our customers’ experience and making continuous improvements in app launch times</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://i0.wp.com/doordash.engineering/wp-content/uploads/2019/01/cropped-doordash_icon.jpg?fit&#x3D;192%2C192&amp;ssl&#x3D;1" alt=""><span class="kg-bookmark-author">DoorDash Engineering Blog</span><span class="kg-bookmark-publisher">Filip Busic</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://doordash.engineering/wp-content/uploads/2023/01/jake-grella-JV-EwgPrpwI-unsplash-e1674862556595.jpg" alt=""></div></a></figure><h2 id="optimizing-code-performance">Optimizing code performance</h2><p>In this article you'll learn about even more small tweaks you can make to Swift code that would optimize for performance. I love how Avi includes the "price table" - the tradeoffs for each of the suggestions 👍</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://betterprogramming.pub/9-ways-to-boost-your-swift-code-performance-56e0986dd9ec?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">9 Ways to Boost Your Swift Code Performance</div><div class="kg-bookmark-description">Some tips on squeezing Swift for speed</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg" alt=""><span class="kg-bookmark-author">Better Programming</span><span class="kg-bookmark-publisher">Avi Tsadok</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://miro.medium.com/max/1200/1*xa2BS9HB9cgeqNnlzumBvA.jpeg" alt=""></div></a></figure><h2 id="improving-linting-speed">Improving linting speed</h2><p>Many of us use SwiftLint, and if you don't - it's a good idea to add it to the project. <br>Xcode 14 introduced a new warning, notifying us of a previously non-obvious fact - with the default setup, SwiftLint is ran on all source files in the project, even for incremental builds, when only one file was changed, for example.<br>So the incremental builds are slower than they could be - and on large projects this could be a noticeable difference. </p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/02/image.png" class="kg-image" alt loading="lazy" width="1232" height="196" srcset="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w600/2023/02/image.png 600w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/size/w1000/2023/02/image.png 1000w, https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/02/image.png 1232w" sizes="(min-width: 720px) 720px"></figure><p>So what can we do? If we just accept Xcode's suggestion, it will just silence the warning. Gladly the warning is useful here - it hints that we can configure it to work together with incremental builds, so it would only run on files that changed.  </p><p>Steven here made a detailed write-up on how to configure this in Xcode, so you get faster incremental builds:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/steven851007/SwiftLint_build_phase_example?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - steven851007/SwiftLint_build_phase_example</div><div class="kg-bookmark-description">Contribute to steven851007/SwiftLint_build_phase_example development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">steven851007</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/f6a4ee03afe8609df9555638c915e63da2679be2e6b07dda3ddd36c4e23fa9d4/steven851007/SwiftLint_build_phase_example" alt=""></div></a></figure><h2 id="formatting-json-strings">Formatting JSON strings</h2><p>A small reminder that we can write JSON strings rich with quotation marks without escaping them - keeping the readability of the JSON.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The best ways to streamline working with JSON strings in Swift that I&#39;ve been using:<br><br>• Use triple quotes<br>• Use the pound character <br><br>What others would you add?<a href="https://twitter.com/hashtag/iosdev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdev</a> <a href="https://twitter.com/hashtag/swiftlang?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#swiftlang</a> <a href="https://t.co/veUZnxTk85?ref=ioscodereview.com">pic.twitter.com/veUZnxTk85</a></p>&mdash; Catalin Patrascu (@cpatrascudev) <a href="https://twitter.com/cpatrascudev/status/1620794707784654849?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 1, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-testing">On testing</h2><p>It's not the first time I share one of Jason's thoughts. I find most of what he writes extremely insightful. If you're still on Twitter, make sure to give him a follow!</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">When writing a test for a class, don&#39;t make it your focus to test all the class&#39;s methods.<br><br>Instead, make it your focus to test all the class&#39;s behaviors.<br><br>This way the tests will be more likely to possess an important quality: meaning.</p>&mdash; Jason Swett (@JasonSwett) <a href="https://twitter.com/JasonSwett/status/1620801148486848512?ref_src=twsrc%5Etfw&ref=ioscodereview.com">February 1, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p></p><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://pasteapp.io/?ref=ioscodereview">Paste</a> for sponsoring this issue (and here's their <a href="https://pasteapp.notion.site/Join-Paste-Team-0499145c46fa46258d873bdb4ba05213?ref=ioscodereview.com">iOS/macOS developer job posting</a>).<br>I'm curious if you found one of the tips particularly interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #41 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to the 41st issue of  iOS Code Review 👋 I hope you enjoy the reading!

💎 Supporter of the week - Coduo 💎

Coduo lets you share and collaborate in Xcode by streaming your Xcode project live into any browser, with full 2-way control.

Simply invite a friend with a ]]></description>
        <link>https://ioscodereview.com/issues/41/</link>
        <guid isPermaLink="false">63c92229d7f57f003d8d9e33</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 19 Jan 2023 05:15:00 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there, <br>Welcome to the 41st issue of  iOS Code Review 👋 I hope you enjoy the reading!</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Supporter of the week - Coduo 💎</strong><br><br><strong>Coduo</strong> lets you share and collaborate in Xcode by streaming your Xcode project live into any browser, with full 2-way control.<br><br>Simply invite a friend with a <strong>Coduo</strong> link, they open it in their browser, and just like magic - you are both working on the same Xcode project, with voice chat and full mouse &amp; keyboard control for both users. <br><br><strong><a href="https://apps.apple.com/us/app/coduo-pair-coding-for-xcode/id6443565833?ref=ioscodereview.com">Try Now</a></strong></div></div><h2 id="my-favorite-architecture">My favorite architecture</h2><p>Here's my favorite architecture stack for UIKit apps. I'm planning to write more about the different aspects of it - got a few questions in the comments there. What would you like to hear about first? (let me know by replying to this email)</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The architecture used (my goto):<br>- coordinators<br>- MVVM<br>- repository pattern w/ simple networking &amp; Codable<br>- UIKit with SwiftUI previews<br>- Modern collection views w/ compositional layout &amp; diffable datasources<br>- Container view controllers<br>- Design system w/ UIButton.Configuration</p>&mdash; Marina Gornostaeva ✨ (@hybridcattt) <a href="https://twitter.com/hybridcattt/status/1612559829889085446?ref_src=twsrc%5Etfw&ref=ioscodereview.com">January 9, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="vstack-lazyvstack-vs-list">VStack, LazyVStack vs List</h2><p>Here Pitt compares the performance of the three options, on a real app. Excellent explanation of the differences, and tl;dr - never use <code>VStack</code> for lists with many elements.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/yrly21IFQdY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Performance between LazyVStack, VStack and List #SwiftUI"></iframe></figure><p>In case you need to implement a long list with infinite scrolling, here's Donny summarizing how to achieve it with <code>LazyVStack</code> and <code>List</code>:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.donnywals.com/implementing-an-infinite-scrolling-list-with-swiftui-and-combine/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Implementing an infinite scrolling list with SwiftUI and Combine</div><div class="kg-bookmark-description">Learn how to use SwiftUI’s onAppear and Combine to build a List that scrolls forever. As a bonus, you’ll also see how you can achieve the same with a LazyVStack.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.donnywals.com/wp-content/uploads/cropped-site-icon-270x270.png" alt=""><span class="kg-bookmark-author">Donny Wals</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.donnywals.com/wp-content/uploads/dw_header.jpg" alt=""></div></a></figure><h2 id="on-technical-debt">On technical debt</h2><p>Loving the analogies with the financial world. Technical debt is like actual debt, we borrow to be able to afford something we otherwise can't. Improving or cleaning up code is like an investment - we spend time to get something in return later.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">How do you decide whether to clean up a piece of code or to leave it alone?<br><br>And how do you decide how much to clean it up?<br><br>Think of it like this: every cleanup job is a bet that your time spent will be paid back by easier future maintenance. Aim for sound bets.</p>&mdash; Jason Swett (@JasonSwett) <a href="https://twitter.com/JasonSwett/status/1611104443105267719?ref_src=twsrc%5Etfw&ref=ioscodereview.com">January 5, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="unwrapping-optionals">Unwrapping optionals</h2><p>Three ways to unwrap an optional, shaped as a meme:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">(from <a href="https://twitter.com/DonnyWals?ref_src=twsrc%5Etfw&ref=ioscodereview.com">@DonnyWals</a>) <a href="https://t.co/mqzCDszyLG?ref=ioscodereview.com">pic.twitter.com/mqzCDszyLG</a></p>&mdash; a meme page to check while Xcode is indexing files (@ios_memes) <a href="https://twitter.com/ios_memes/status/1613514390577479680?ref_src=twsrc%5Etfw&ref=ioscodereview.com">January 12, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="is-this-good-code">Is this good code?</h2><p>My galaxy-brain answer to this would be: as long as this function is covered by extensive unit tests, it doesn't matter that much how it's implemented.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Junior eng: this is good code<br>Medior eng: hold my beer 🍺<br>Senior eng: this is good code <a href="https://t.co/YpHvucX3O6?ref=ioscodereview.com">https://t.co/YpHvucX3O6</a></p>&mdash; Willem Spruijt (@wspruijt) <a href="https://twitter.com/wspruijt/status/1615346728940732416?ref_src=twsrc%5Etfw&ref=ioscodereview.com">January 17, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://apps.apple.com/us/app/coduo-pair-coding-for-xcode/id6443565833?ref=ioscodereview.com">Coduo</a> for sponsoring this issue.<br>I'm curious if you found one of the tips particulary interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #40 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to the 40th edition of  iOS Code Review! I hope you had a wonderful holiday season and a happy new year. I&#39;m wishing that 2023 will be a better year than the last.
In this issue, I have a variety of tips to share with ]]></description>
        <link>https://ioscodereview.com/issues/40/</link>
        <guid isPermaLink="false">63b6b20d09641c003df0d26e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 05 Jan 2023 05:13:42 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,<br>Welcome to the 40th edition of  iOS Code Review! I hope you had a wonderful holiday season and a happy new year. I'm wishing that 2023 will be a better year than the last.<br>In this issue, I have a variety of tips to share with you. I hope you enjoy the reading! </p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><strong>💎 Sponsor of the week - dataTile for Simulator 💎</strong><br><br>Forget about console debugging! Reduce development time by using <strong>dataTile for Simulator</strong>, an Xcode companion app. It works with your Xcode Simulator, automatically detects any debug data you log, and prominently displays it in a beautiful UI 😍 <br><br>It requires no configuration, project changes or 3rd party code, if you're using Apple's unified logging. It just works!<br><br><a href="https://www.producthunt.com/posts/datatile-for-simulator?ref=ioscodereview.com"><strong>Try for free 😎</strong></a></div></div><h2 id="ordered-dictionary-anyone">Ordered dictionary anyone?</h2><p>Did you know that Swift has an official package with ordered versions of our well-known data structures: <code>OrderedDictionary</code> and <code>OrderedSet</code>? They live in a separate SPM package because the Swift core team decided that such components should live in separate packages until they are deemed worthy of inclusion in the standard library. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/apple/swift-collections?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - apple/swift-collections: Commonly used data structures for Swift</div><div class="kg-bookmark-description">Commonly used data structures for Swift. Contribute to apple/swift-collections development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt=""><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">apple</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/a403bc6d3a033e3947d7fafbd8acfbf65cd9aab39316d2c4f535408d07a3dca9/apple/swift-collections" alt=""></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.advancedswift.com/ordereddictionary/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">OrderedDictionary In Swift</div><div class="kg-bookmark-description">Learn how and when to use OrderedDictionary, provided by the swift-collections package, in Swift.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.advancedswift.com/favicon.ico" alt=""><span class="kg-bookmark-author">Advanced Swift</span><span class="kg-bookmark-publisher">Robert Pieta</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1607296393394-6e25d0fc15cc?crop&#x3D;entropy&amp;cs&#x3D;tinysrgb&amp;fit&#x3D;max&amp;fm&#x3D;jpg&amp;ixid&#x3D;MnwxMTc3M3wwfDF8c2VhcmNofDIzfHxvcmRlcnxlbnwwfHx8fDE2MTgxNzU5NTI&amp;ixlib&#x3D;rb-1.2.1&amp;q&#x3D;80&amp;w&#x3D;2000" alt=""></div></a></figure><h2 id="using-label-in-swiftui">Using Label in SwiftUI</h2><p>Whenever we want to show an icon and text together, <code>Label</code> comes to the rescue. It supports accessibility out of the box, and offers the ability to easily hide the icon or text using the modifier <code>.labelStyle(.iconOnly)</code> , while preserving the accessibility information. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://sarunw.com/posts/swiftui-label-a-standard-way-to-label-user-interface-items/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">SwiftUI Label: A standard way to label user interface items | Sarunw</div><div class="kg-bookmark-description">A label might seem trivial, but it plays an important role in SwiftUI. Let’s learn about this simple view.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://sarunw.com/favicon-96x96.png" alt=""><span class="kg-bookmark-author">Sarunw</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://sarunw.com/images/og/swiftui-label-a-standard-way-to-label-user-interface-items.png" alt=""></div></a></figure><h2 id="accessibility-of-images-in-swiftui">Accessibility of images in SwiftUI</h2><p>On a related note, we can enrich images with accessibility text in another way - by simply providing a localizable string with the image name as a key. It works out of the box, with no additional modifiers needed on the image 😍</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://nilcoalescing.com/blog/ImageAccessibilityLabelsFromLocalizableStringsFiles/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Image accessibility labels from Localizable.strings files</div><div class="kg-bookmark-description">When we add an image name to a Localizable.strings file, SwiftUI automatically uses it for the image accessibility label.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://nilcoalescing.com/static/favicon-196.3144yfFxGDjHn3y7r_G6fW5u_yFMZXRohR8vAApshf8.png" alt=""><span class="kg-bookmark-author">Nil Coalescing</span><span class="kg-bookmark-publisher">Natalia Panferova</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://nilcoalescing.com/static/blog/ImageAccessibilityLabelsFromLocalizableStringsFiles/banner.x0KAQ3yGnjXj2tsVFyMa0PNamLsqr5WJryOF8usnOhA.png" alt=""></div></a></figure><h2 id="better-xctest-failure-messages">Better XCTest failure messages</h2><p>When we use <code>XCTAssertNil(sut.optionalProperty)</code>, the failure message in case of assert failing will be not so helpful - "XCTAssertNil failed". By using <code>XCTAssertEqual(sut.optionalProperty, nil)</code> instead, we will get the actual value of the property in the failure message.<br>A few more suggestions on asserting optionals better, shared by Jon Reid:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://qualitycoding.org/unit-test-optionals-swift/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to Unit Test Optionals in Swift | Quality Coding</div><div class="kg-bookmark-description">You have a Swift optional value. How can you write an XCTest assertion to verify it, while getting the most from assertion failure messages?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://qualitycoding.org/wp-content/uploads/2020/06/favicon.png" alt=""><span class="kg-bookmark-author">Quality Coding</span><span class="kg-bookmark-publisher">Jon Reid</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://qualitycoding.org/wp-content/uploads/2020/09/ghost.png" alt=""></div></a></figure><h2 id="accessing-view-controllers-view">Accessing view controller's view</h2><p><code>UIViewController</code>'s <code>view</code> is lazy, created the first time <code>.view</code> is accessed. When we want to access it without triggering the lazy creation, only getting the view if it already exists - there's <code>viewIfLoaded</code> property. Available since 2015, shared by Peter in 2019, and I saw this yesterday, in 2023 😅</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">TIL UIViewController has viewIfLoaded since iOS 9. <a href="https://t.co/XSlKH7lJL1?ref=ioscodereview.com">pic.twitter.com/XSlKH7lJL1</a></p>&mdash; Peter Steinberger (@steipete) <a href="https://twitter.com/steipete/status/1189242402659356675?ref_src=twsrc%5Etfw&ref=ioscodereview.com">October 29, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://www.producthunt.com/posts/datatile-for-simulator?ref=ioscodereview.com">dataTile for Simulator</a> for sponsoring this issue.<br>I'm curious if you found one of the tips particulary interesting - let me know by replying to this email!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #39 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to issue #39, the last one in 2022. I wish you wonderful holidays, and see you on January 5 👋


Supporting webp images with PHPicker

Are  you using PHPickerViewController for photo library imports, and access images using loadObject(ofClass:)? It turns out, this method doesn&#39;t support ]]></description>
        <link>https://ioscodereview.com/issues/39/</link>
        <guid isPermaLink="false">638f7f6738ff30003d9be40c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 15 Dec 2022 04:06:43 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,<br>Welcome to issue #39, the last one in 2022. I wish you wonderful holidays, and see you on January 5 👋</p><h2 id="supporting-webp-images-with-phpicker">Supporting webp images with PHPicker</h2><p>Are  you using <code>PHPickerViewController</code> for photo library imports, and access images using <a href="https://developer.apple.com/documentation/foundation/nsitemprovider/2888336-loadobject?ref=ioscodereview.com"><code>loadObject(ofClass:)</code></a>? It turns out, this method doesn't support some image formats, such as <code>webp</code> images. You can use <a href="https://developer.apple.com/documentation/foundation/nsitemprovider/2888331-loaddatarepresentation?ref=ioscodereview.com"><code>loadDataRepresentation(forTypeIdentifier: "public.image", completionHandler:)</code></a> instead. </p><h2 id="equality-vs-identity">Equality vs Identity</h2><p>How is <code>===</code> different from <code>==</code> ?<code>===</code> checks if it's the same instance, and is available only for classes. But why do we almost never have to use it? </p><p>All <code>NSObject</code>s ( <code>UIView</code> , <code>UIViewControllers</code>, etc) get a default <code>Equatable</code> conformance that uses Objective-C's <code>isEqual:</code> , which in turn compares instances, like <code>===</code> would. So when writing checks like <code>if sender == myButton</code>, we <em>actually mean </em><code>===</code>, but can save one character thanks to Swift's interoperability with Objective-C.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Swift gives us two equality operators, == and ===<br><br>== tests that two things are equal like 5 == 5<br><br>=== is the identity operator, which checks whether two instances of a class point to the same memory<a href="https://twitter.com/hashtag/ios?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#ios</a> <a href="https://twitter.com/hashtag/swift?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#swift</a> <a href="https://twitter.com/hashtag/iosdevbasics?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdevbasics</a> <a href="https://twitter.com/hashtag/iosdevelopment?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdevelopment</a> <a href="https://twitter.com/hashtag/iosdev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdev</a> <a href="https://twitter.com/hashtag/iosdevs?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdevs</a> <a href="https://twitter.com/hashtag/iosdevelopers?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosdevelopers</a></p>&mdash; Viktoria Likhotkina (@viktoriia_li) <a href="https://twitter.com/viktoriia_li/status/1603126772656230403?ref_src=twsrc%5Etfw&ref=ioscodereview.com">December 14, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><div class="kg-card kg-callout-card kg-callout-card-white"><div class="kg-callout-text"><strong>💎 Supporter of the week - Codelime 💎</strong><br><br><strong>Codelime</strong> is a powerful code snippet manager with many dev tools for iOS development. Save and manage your code snippets across iPhone, iPad and Mac with Codelime.<br><br>Take advantages of many dev tools available in Codelime (Hash, Text Case, Color Picker, Generate Asset Catalog, Make Pretty Code Snippet, ...) to boost your every day iOS development workflow.<br><br>Made by indie developers. <a href="https://onmyway133.com/codelime/?ref=ioscodereview.com">Try it for free ↗️</a></div></div><h2 id="more-formatter-coolness">More formatter coolness</h2><p>I can't stop being amazed by all the different features available in formatters out of the box:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I didn&#39;t know, there is a possibility to set a custom positive prefix to a number formatter...🤯 Very handy!<a href="https://twitter.com/hashtag/stillLearning?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#stillLearning</a> <a href="https://twitter.com/hashtag/swift?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#swift</a> <a href="https://twitter.com/hashtag/iosDev?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#iosDev</a> <a href="https://t.co/Her1zsL1ca?ref=ioscodereview.com">pic.twitter.com/Her1zsL1ca</a></p>&mdash; Pavel Zak (@myridiphis) <a href="https://twitter.com/myridiphis/status/1597869794921164800?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 30, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="readable-large-numbers">Readable large numbers</h2><p>We can arbitrarily add <code>_</code>'s inside any type of number literal - integers, floats or even hex numbers:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.swiftwithvincent.com/tips/large-number-separators?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">large number separators — Swift with Vincent</div><div class="kg-bookmark-description">Here’s the code if you want to experiment with it!</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://images.squarespace-cdn.com/content/v1/63139bb1e1a1a078e071f30c/bd40c4d4-dc8b-48b7-a0cc-2209de7d1ab6/favicon.ico" alt=""><span class="kg-bookmark-author">Swift with Vincent</span><span class="kg-bookmark-publisher">Vincent Pradeilles</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://static1.squarespace.com/static/63139bb1e1a1a078e071f30c/63662f7ff6d8dc0afb976b61/6366413c2ff5e829c324b725/1667647548462/NumberSeparator.gif?format&#x3D;1500w" alt=""></div></a></figure><h2 id="my-top-5-tips">My top 5 tips</h2><p>I teamed up with Vincent to record a 20 min. video where I share my top tips to improve your Swift code. Some of them have been featured in the newsletter earlier, but some have not:</p><ul><li>Avoiding Retain Cycles with Combine or RxSwift </li><li>Typesafe Identifiers </li><li>Managing Complex UI States </li><li>Never Forget to Call a Completion Handler </li><li>Simplifying UI Code with Layout Margins</li><li>Typesafe Strings and Images</li></ul><p>If you haven't seen the video yet, do check it out ☺️</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/Frpnb_aqkX4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="5 Expert Tips to Improve Your Swift Code 💪 (w/ guest @Marina Gornostaeva)"></iframe></figure><p>✌️<br>Alright, that's it for today! Thank you to <a href="https://onmyway133.com/codelime/?ref=ioscodereview.com">Codelime</a> for sponsoring this issue.<br>I'm curious if you found one of the tips particulary interesting - let me know by replying to this email!</p><p>Happy holidays 🕎🎄</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #38 ]]></title>
        <description><![CDATA[ Hi there,
welcome to issue #38!


Modern collection views

A lot has changed in UITableView and UICollectionView APIs in the recent years. While before we would subclass UICollectionViewCell and implement UICollectionViewDataSource and UICollectionViewDelegate protocols, the modern ways look nothing like that.

Now we provide cell content using cell configurations, dequeue ]]></description>
        <link>https://ioscodereview.com/issues/38/</link>
        <guid isPermaLink="false">63886d1847671a003d1cde81</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 01 Dec 2022 05:37:36 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,<br>welcome to issue #38!</p><h2 id="modern-collection-views">Modern collection views</h2><p>A lot has changed in <code>UITableView</code> and <code>UICollectionView</code> APIs in the recent years. While before we would subclass <code>UICollectionViewCell</code> and implement <code>UICollectionViewDataSource</code> and <code>UICollectionViewDelegate</code> protocols, the modern ways look nothing like that. </p><p>Now we provide cell content using <em><a href="https://developer.apple.com/documentation/uikit/uicollectionviewcell/3600949-contentconfiguration?ref=ioscodereview.com">cell configurations</a>, </em>dequeue reusable cells using <em><a href="https://developer.apple.com/documentation/uikit/uicollectionview/cellregistration?ref=ioscodereview.com">cell</a> and <a href="https://developer.apple.com/documentation/uikit/uicollectionview/supplementaryregistration?ref=ioscodereview.com">supplementary registrations</a></em>, use <em><a href="https://developer.apple.com/documentation/uikit/uicollectionviewdiffabledatasource?ref=ioscodereview.com">diffable data sources</a></em> for safe data with animatable updates, and use <em><a href="https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout?ref=ioscodereview.com">compositional layouts</a></em> for grids, lists and carousels. All of this is available iOS 14+.</p><p>Apple has comprehensive articles with explanations and sample code, going over these concepts and showing how they play together: </p><p><a href="https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views?ref=ioscodereview.com"><strong>Implementing Modern Collection Views</strong></a><br><a href="https://developer.apple.com/tutorials/app-dev-training/using-content-views?ref=ioscodereview.com"><strong>Implementing Custom Cells Using Content Views</strong></a><br></p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><em><strong>💎 Sponsor of this issue - TelemetryDeck</strong></em><br><br>Your app's users are mostly satisfied, but let's make them fall in LOVE with your app! Let's make them loyal ambassadors for your idea, tell their friends all about it! <br><br>We believe that by continuously improving your app's performance, design and experience through respectful, privacy-first, real-time analytics, it can really shine. <br><br>Start for free at <a href="https://telemetrydeck.com/?source=ioscodereview" rel="noreferrer"><strong>telemetrydeck.com</strong></a></div></div><h2 id="xcconfig-files">xcconfig files</h2><p>Xcconfig files are considered an advanced feature, only reserved for larger projects. That's my impression, at least. But the idea is quite simple - we can override build settings of a target via plain text files. </p><p>When we have multiple targets with mostly same build settings, it's better to use xcconfig files for specifying the parameters that are different - the contents of .xcodeproj files are not easily trackable in source control, and using xcconfig files solves that. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.danijelavrzan.com/posts/2022/11/xcode-configuration/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to manage build settings using Xcode configuration files | Danijela’s blog</div><div class="kg-bookmark-description">You use Xcode build configuration files to define all sorts of useful build settings. You can open them with different text editors outside of Xcode and all properties are in plain text. It’s common to use them for managing constants across different environments.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.danijelavrzan.com/images/favicon.png" alt=""><span class="kg-bookmark-author">Danijela&#x27;s blog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://danijelavrzan.com/images/posts/2022/11/xcode-configuration.png" alt=""></div></a></figure><h2 id="custom-screenshot-support">Custom screenshot support</h2><p>TIL about <code><a href="https://developer.apple.com/documentation/uikit/uiscreenshotservicedelegate?ref=ioscodereview.com">UIScreenshotServiceDelegate</a></code> - allowing you to support custom PDF export via the native screenshot functionality. To see it an action, try taking a screenshot in Safari - there will be a segment control at the top, choosing between just the screenshot or a PDF of the whole page. </p><blockquote>When the user captures a screenshot of your app’s windows, UIKit calls the methods of this protocol to retrieve PDF data for those windows, and then it provides that data to the user.</blockquote><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">One API I wish more apps would support is integration into the iOS screenshot system via `UIScreenshotServiceDelegate`.<br><br>This allows for very quick Full Page PDF Exports of your app 👌 <a href="https://t.co/n45EazidKd?ref=ioscodereview.com">pic.twitter.com/n45EazidKd</a></p>&mdash; Matthias Tretter (@myell0w) <a href="https://twitter.com/myell0w/status/1597245043407958016?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 28, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="dummy-data-for-previews">Dummy data for previews</h2><p>To reduce app size and memory footprint of your app, make sure that the test data for SwiftUI previews is not included in release builds. You can wrap the code to exclude in <code>#if DEBUG</code>. <br>Another option is to use "development assets" - a relatively new build setting in Xcode. You can specify which files (code or assets) will be stripped during release builds. Read more: <a href="https://www.avanderlee.com/xcode/development-assets-preview-catalog/?ref=ioscodereview.com" rel="bookmark">Development Assets in Xcode to enrich SwiftUI Previews</a></p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">In his talk <a href="https://twitter.com/dimsumthinking?ref_src=twsrc%5Etfw&ref=ioscodereview.com">@dimsumthinking</a> mentioned to create static vars of model objects for previews.<br><br>I wanted to add two ideas:<br><br>1. Create multiple ones to see how it might stretch your layout.<br><br>2. Put the extensions in the Preview Content folder of your apps (won’t be shipped).<br><br>✌🏻 <a href="https://t.co/kkClFbtDHC?ref=ioscodereview.com">https://t.co/kkClFbtDHC</a> <a href="https://t.co/NxZG9R83m7?ref=ioscodereview.com">pic.twitter.com/NxZG9R83m7</a></p>&mdash; Stefan (@stefanjblos) <a href="https://twitter.com/stefanjblos/status/1590249340349870081?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 9, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="coding-is-like-gardening">Coding is like gardening</h2><p>A wonderful analogy, indeed the code is not built once and done, but grows and evolves over time. I'm a big proponent of building code in a way that welcomes future changes.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">One of the best mindsets you can adopt around coding is to think of it like gardening instead of construction or architecture. You plant seeds based on an initial plan and conditions. Then you constantly monitor the health of the garden and make adjustments as needed.</p>&mdash; Juan Carlos Fontecha (@jufontech) <a href="https://twitter.com/jufontech/status/1597660669054255106?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 29, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️<br>Alright, that's it for today. <br>Thank you to <a href="https://telemetrydeck.com/?source=ioscodereview">TelemetryDeck</a> for sponsoring this issue!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #37 ]]></title>
        <description><![CDATA[ Hi there,
Welcome to the 37th issue 👋

Apologies for sending this issue a day late - I&#39;ve had a small self-inflicted injury and had to go to the hospital just in case. All is well in the end though 😊

You might have noticed a different sender and layout ]]></description>
        <link>https://ioscodereview.com/issues/37/</link>
        <guid isPermaLink="false">63761997398507003d6555a1</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Fri, 18 Nov 2022 03:51:59 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,<br>Welcome to the 37th issue 👋</p><p>Apologies for sending this issue a day late - I've had a small self-inflicted injury and had to go to the hospital just in case. All is well in the end though 😊</p><p>You might have noticed a different sender and layout this time - that's because I've switched from Revue to a content platform called Ghost. It's a really powerful platform, and I will be expanding the site, such as adding the ability to search among all past issues. Stay tuned :) </p><hr><h2 id="structuring-swiftui-views">Structuring SwiftUI views</h2><p>SwiftUI is relatively new, but there are other declarative UI languages with history. React is a popular web frontend framework, and there's a lot we can learn from there. <br>One example is a pattern where we break down views that load data into two:<br>The outer view is a loading component that's aware of the networking, and the inner view is a more "stupid" view with just UI elements. <br>The inner view then can then be reused - across features, for previews in app settings, and for SwiftUI previews.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">ReactJS has a pattern called container and presentation components. This pattern suggest you fetch data + more in container component and pass it down to presentation components. Your presentation components are reusable components. <a href="https://twitter.com/hashtag/SwiftUI?src=hash&ref_src=twsrc%5Etfw&ref=ioscodereview.com">#SwiftUI</a> <a href="https://t.co/5EMjfc2WUR?ref=ioscodereview.com">pic.twitter.com/5EMjfc2WUR</a></p>&mdash; Mohammad Azam (@azamsharp) <a href="https://twitter.com/azamsharp/status/1588692969170739200?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 5, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="organizing-test-image-assets">Organizing test image assets</h2><p>Good tip here to avoid cluttering your app with images you only use for testing - saving on both app size and compile time:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Speed up your Xcode builds by leaving images for testing OUTSIDE of (Preview) Asset catalogs; just drop them in a folder among tests and fetch them via Bundle.<br>No more expensive asset catalog compiling!<a href="https://t.co/3yRr3uk9R2?ref=ioscodereview.com">https://t.co/3yRr3uk9R2</a> <a href="https://t.co/OK1Y6SZXpj?ref=ioscodereview.com">pic.twitter.com/OK1Y6SZXpj</a></p>&mdash; Daniel Kašaj (@DanielKasaj) <a href="https://twitter.com/DanielKasaj/status/1588449011446464514?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 4, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="project-quality-of-life">Project quality-of-life</h2><p>Completely agree with the list here. When there's no warnings in the project, the console log isn't cluttered, etc - it's so much easier to spot new issues right when they are introduced:</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Things that should be vigilantly defended in your iOS project, at all times:<br>- A working build<br>- Clear build output (e.g. warnings)<br>- Clear console behavior<br>- NO Auto Layout warnings<br>- Any CI/&#39;CD&#39; systems<br> <br>All are easy to let deteriorate, yet, critical day-to-day. Fix it early.</p>&mdash; josh avant 📱 (@joshavant) <a href="https://twitter.com/joshavant/status/1588219036197785600?ref_src=twsrc%5Etfw&ref=ioscodereview.com">November 3, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="urlrequest-cache-policies">URLRequest cache policies</h2><p>Excellent article to understand the various cache policies and how they affect your iOS application when sending HTTP requests with URLRequest:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://tanaschita.com/20221031-managing-cache-when-working-with-urlsession-in-ios/?ref=ioscodereview.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Understanding different cache policies when working with URLRequest in Swift</div><div class="kg-bookmark-description">Learn how to manage cache when sending HTTP requests in your iOS applications. Learn about the differences between the policies useProtocolCachePolicy, reloadIgnoringLocalCacheData, reloadIgnoringLocalAndRemoteCacheData and more.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://tanaschita.com/favicon.ico" alt=""></div></div><div class="kg-bookmark-thumbnail"><img src="https://tanaschita.com/og/20221031-managing-cache-when-working-with-urlsession-in-ios.png" alt=""></div></a></figure><h2 id="xcode-power-tips">Xcode power tips</h2><p>If you want to become more efficient with Xcode, watch this 17-minute video. I've been using Xcode for over a decade, and I learned so much. The more efficient we are, the more time we have to actually focus on problemsolving and code ☺️</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/40imnmzsmxk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="31 Xcode Tips &amp; Tricks - 2022 | Xcode 14"></iframe></figure><p>🤘</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><strong>💎 Sponsor of the week - Codelime</strong><br><br><a href="https://onmyway133.com/codelime/?ref=ioscodereview.com">Codelime</a> is a powerful code snippet manager with many dev tools for iOS development. Save and manage your code snippet across iPhone, iPad and Mac with Codelime.<br><br>Take advantages of many dev tools available in Codelime (Hash, Text Case, Color Picker, Generate Asset Catalog, Make Pretty Code Snippet, ...) to boost your every day iOS development workflow.<br><br>The app is made by indie developers <a href="https://twitter.com/onmyway133?ref=ioscodereview.com">Khoa 🔥</a> and <a href="https://twitter.com/khuong291?ref=ioscodereview.com">Kenny 🌴</a></div></div><p>Alright, that’s it for today.</p><p>If you enjoyed this issue, you can help grow the newsletter by spreading the word!</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ [bonus issue] Issue #36 ]]></title>
        <description><![CDATA[ Hi there,

Yesterday I&#39;ve sent out the issue #35, and it was flagged as spam by Gmail. It was due to technical problems on Revue side, not sure what exactly. They got fixed after I reached out to support, and now the emails are delivered ok.

I know ]]></description>
        <link>https://ioscodereview.com/issues/36/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a58d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Fri, 04 Nov 2022 06:07:52 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Yesterday I've sent out the issue #35, and it was flagged as spam by Gmail. It was due to technical problems on Revue side, not sure what exactly. They got fixed after I reached out to support, and now the emails are delivered ok.</p><p>I know that a lot of you are looking forward to receiving the newsletter, but I didn't want to just redeliver the same email again. Hence this bonus issue with two great articles 😊</p><p>If you're on gmail, check your spam folder for the previous email, and please mark it as "not spam" 🙏 If you're not on Gmail, I hope you don't mind the bonus issue 💚</p><p>I am investigating changing to a more reliable email platform, so the email layout might be slightly different next time.</p><hr><h2 id="managing-secrets">Managing secrets</h2><p>How do we store secrets securely on the client? This NSHipster article goes over the pros and cons of hardcoding values in code, using xcconfig files, or providing API keys over the network.</p><h3 id="secret-management-on-ios-nshipster"><a href="https://nshipster.com/secrets/?ref=ioscodereview.com">Secret Management on iOS - NSHipster</a></h3><p><br></p><h2 id="writing-a-perfect-pull-request">Writing a perfect pull request</h2><p>When you make a good pull request, you receive a quick review, clear feedback, and don't get too many questions such as "why did you do it like this?". This usually has almost nothing to do with the actual code changes! In this article you'll find tips on how to make your pull requests great.</p><h3 id="how-to-write-the-perfect-pull-request-level-up-coding"><a href="https://levelup.gitconnected.com/how-to-write-the-perfect-pull-request-d044625ace98?gi=6a8f584c2877&ref=ioscodereview.com">How To Write The PERFECT Pull Request  | Level Up Coding</a></h3><p><br></p><p>🤘</p><p>Thank you for bearing with me, and see you in two weeks!</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #35 ]]></title>
        <description><![CDATA[ Hi there,

Welcome to the issue #35 👋 Enjoy!


Better test assertions

We all want the tests to immediately tell us that something is wrong, and here&#39;s some advice on how to achieve that by using XCTAssertEqual instead of just XCTAssert:












Multiple accessibility labels

With accessibilityUserInputLabels, we can provide ]]></description>
        <link>https://ioscodereview.com/issues/35/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a58e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 03 Nov 2022 05:33:05 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Welcome to the issue #35 👋 Enjoy!</p><hr><h2 id="better-test-assertions">Better test assertions</h2><p>We all want the tests to immediately tell us that something is wrong, and here's some advice on how to achieve that by using <code><a href="https://developer.apple.com/documentation/xctest/xctassertequal?ref=ioscodereview.com">XCTAssertEqual</a></code> instead of just <code><a href="https://developer.apple.com/documentation/xctest/xctassert?ref=ioscodereview.com">XCTAssert</a></code>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1587816571556466689?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1587917123967668224?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="multiple-accessibility-labels">Multiple accessibility labels</h2><p>With <code><a href="https://developer.apple.com/documentation/objectivec/nsobject/3197989-accessibilityuserinputlabels?ref=ioscodereview.com">accessibilityUserInputLabels</a></code>, we can provide multiple strings by which the user can address an element.</p><p>And a reminder not to use <code><a href="https://developer.apple.com/documentation/uikit/uiaccessibilityelement/1619577-accessibilitylabel?ref=ioscodereview.com">accessibilityLabel</a></code> for internal strings for UI tests, there's <code><a href="https://developer.apple.com/documentation/uikit/uiaccessibilityidentification/1623132-accessibilityidentifier?ref=ioscodereview.com">accessibilityIdentifier</a></code> for that.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dadederk/status/1580652449463144448?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="system-background">System background</h2><p>Reminder that <code><a href="https://developer.apple.com/documentation/uikit/uicolor/3173145-systemgroupedbackground?ref=ioscodereview.com">UIColor.systemGroupedBackground</a></code> exists, reflecting system background you see on grouped table views, for example in Settings. We can use it in both UIKit and SwiftUI:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/KSlazinski/status/1578619241065893888?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="more-formatters">More formatters</h2><p>Remember <code><a href="https://developer.apple.com/documentation/foundation/listformatter?ref=ioscodereview.com">ListFormatter</a></code> I mentioned last time? Here's an infographic with even more examples of different native formatter APIs.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/DKanunnikoff/status/1578451043507109888?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="the-traps-of-swift-concurrency">The traps of Swift Concurrency</h2><p>There's many things the compiler doesn't check, and often the behaviour of async/await is not what you'd expect. Lots of traps to fall into... For example, actors are not as protective as they seem at first glance. Many examples of problems and solutions in this article by <a href="https://twitter.com/kulik_wojciech?ref=ioscodereview.com">@kulik_wojciech</a>.</p><p>It's a longer article going deep into how concurrency works, make sure to save it if you don't have time to read it yet :)</p><h3 id="swift-concurrency-things-they-don-t-tell-you"><a href="https://wojciechkulik.pl/ios/swift-concurrency-things-they-dont-tell-you?ref=ioscodereview.com">Swift Concurrency – Things They Don’t Tell You</a></h3><p><br></p><h2 id="sponsor-of-the-week-codelime">Sponsor of the week - Codelime</h2><p><a href="https://onmyway133.com/codelime/?ref=ioscodereview.com">Codelime</a> is a powerful code snippet manager with many dev tools for iOS development. Save and manage your code snippet across iPhone, iPad and Mac with Codelime.</p><p>Take advantages of many dev tools available in Codelime (Hash, Text Case, Color Picker, Generate Asset Catalog, Make Pretty Code Snippet, ...) to boost your every day iOS development workflow.</p><p>The app is made by 2 indie developers <a href="https://twitter.com/onmyway133?ref=ioscodereview.com">Khoa 🔥</a> and <a href="https://twitter.com/khuong291?ref=ioscodereview.com">Kenny 🌴</a></p><h3 id="codelime-powerful-code-snippet-manager"><a href="https://onmyway133.com/codelime/?ref=ioscodereview.com">Codelime - Powerful code snippet manager</a></h3><p>Powerful code snippet manager</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #34 ]]></title>
        <description><![CDATA[ Hi there,

Welcome to issue #34 👋 Hope you learn something new today!

I also got the first sponsor this time - I&#39;m really excited to be able to get some funds to continue growing the newsletter! I&#39;m already investing them into improving my curation workflow and ]]></description>
        <link>https://ioscodereview.com/issues/34/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a58f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 20 Oct 2022 04:05:16 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Welcome to issue #34 👋 Hope you learn something new today!</p><p>I also got the first sponsor this time - I'm really excited to be able to get some funds to continue growing the newsletter! I'm already investing them into improving my curation workflow and building a custom landing page. If you're looking for a job, check out the sponsored section at the end ☺️</p><hr><h2 id="organising-package-manifests">Organising package manifests</h2><p><code>Package.swift</code> is a Swift file, and that means we can write Swift code in it, for example declare variables and functions, and even call them.</p><p>Are you already using any Swift language features in your package manifest? I'm curious about what other use-cases we can find for this.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/_sa_s/status/1582329921371721729?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="localised-lists">Localised lists</h2><p><code><a href="https://developer.apple.com/documentation/foundation/listformatter?ref=ioscodereview.com">ListFormatter</a></code> composes a localised string from an array of elements, using a grammatically correct way to join the strings for the current locale. You can also customise how each element in the list is formatted by providing an <code><a href="https://developer.apple.com/documentation/foundation/listformatter/3130988-itemformatter?ref=ioscodereview.com">itemFormatter</a></code> property.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1582099132470071296?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="year-formatting">Year formatting</h2><p>Every year it comes up on Twitter around December 30, that using <code>YYYY</code> in date formats is incorrect for displaying dates, as it stands for "week year" which will be wrong around the New Years week.</p><p>This year it's not yet too late to make a fix, so here's a reminder to check your code :)</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twostraws/status/1485239037426339843?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/davedelong/status/1344388020661673985?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/pgor/status/1344352338404929538?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="accessibility-customisations-in-swifui-vs-uikit">Accessibility customisations in SwifUI vs UIKit</h2><p>It's not always clear how to achieve the same accessibility customizations in SwiftUI vs UIKit. Here's a great summary - make sure to save it to your bookmarks for later:</p><h3 id="accessibility-in-swiftui-explained-for-uikit-developers-swiftlee"><a href="https://www.avanderlee.com/swiftui/accessibility-uikit-developers/?ref=ioscodereview.com">Accessibility in SwiftUI explained for UIKit developers - SwiftLee</a></h3><p>Accessibility in SwiftUI works a little different than in UIKit, but with a few tips you'll be able to get up to speed quickly.</p><h2 id="swiftui-performance-tips">SwiftUI performance tips</h2><p>In this article Martin goes over various aspects of SwiftUI development and shares solid advice on avoiding performance issues in your UI code:</p><h3 id="swiftui-performance-tips-martinmitrevski"><a href="https://martinmitrevski.com/2022/04/14/swiftui-performance-tips/?ref=ioscodereview.com">SwiftUI performance tips – martinmitrevski</a></h3><p>SwiftUI has been around for almost 3 years now, and during this period working with it, I’ve noticed few groups of developer mistakes (both mine and from others) that can impact its performance. In this post, we will look at these pitfalls, and their potential solutions.</p><h2 id="-sponsored-jobs-">🧑‍💻 Sponsored Jobs 🧑‍💻</h2><p>My friends at Shape Games are looking for iOS developers:</p><ul><li><a href="https://careers.shapegames.com/jobs/1729911-ios-developer-remote?ref=ioscodereview.com">iOS developer (remote)</a></li><li><a href="https://careers.shapegames.com/jobs/1722970-ios-developer?ref=ioscodereview.com">iOS developer (relocation to Copenhagen)</a></li><li><a href="https://careers.shapegames.com/jobs/1744861-student-ios-developer?ref=ioscodereview.com">Student iOS developer</a></li></ul><p>They’re building the leading sports betting frontend platform. This posting was sponsored (yay!), but also I personally know many people working there, and I've been to their lovely office for meetups countless times. It’s a great mobile team who care about the craft 👍</p><p><br></p><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #33 ]]></title>
        <description><![CDATA[ Hi there,

Welcome to the 33rd issue 👋 We&#39;re back to a classic five-tips structure, and I hope you find something interesting today.

As an innovation, I&#39;ve included a new section at the bottom with featured jobs. They&#39;re not sponsored this time, but I hope ]]></description>
        <link>https://ioscodereview.com/issues/33/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a590</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 06 Oct 2022 04:12:57 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Welcome to the 33rd issue 👋 We're back to a classic five-tips structure, and I hope you find something interesting today.</p><p>As an innovation, I've included a new section at the bottom with featured jobs. They're not sponsored this time, but I hope to get sponsored job or indie app ads in the future. The code tips themselves will never have any promoted content in them, only what I truly think is best ☺️</p><hr><h2 id="traversing-the-view-hierarchy">Traversing the view hierarchy</h2><p>Iterating over superview chain, or parent view controllers, you name it. Awesome trick to replace recursive lookups.</p><p>Have you heard of <code><a href="https://developer.apple.com/documentation/swift/sequence(state:next:)?ref=ioscodereview.com">sequence(first:next)</a></code> ? It's a <code><a href="https://developer.apple.com/documentation/swift/sequence?ref=ioscodereview.com">Sequence</a></code> (the same protocol arrays, dictionaries, and other collections conform to), and can be used with <code>for...in</code> , <code>forEach</code>, <code>map</code>, etc.</p><p><a href="https://developer.apple.com/documentation/swift/sequence(state:next:)?ref=ioscodereview.com">sequence(first:next)</a> generates an iteratable sequence on the fly, each next element being derived from the previous one. As soon as <code>next</code> returns nil, iteration stops. So the <code>next</code> closure can return <code>nil</code>, but elements in the sequence are non-optional. If nil is never returned, the sequence is infinite.</p><p>For example, here's an infinite iteration over even numbers:</p><p><code>for i in sequence(first: 0, next: { $0 + 2 }) { print(i) }</code></p><p>A super neat application for this is to iterate over the view hierarchy, or view controller hierarchy, you name it:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/kyleve/status/1575353657825972224?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="completion-handlers">Completion handlers</h2><p>I really like how we can use typealiases for completion handlers to make code easier to read and refactor:</p><p><code>func do(completion: @escaping ((Result&lt;X, Error&gt;) -&gt; Void)?)</code></p><p>becomes</p><p><code>func do(completion: @escaping CompletionHandler&lt;X&gt;?)</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/v_pradeilles/status/1493925764496044039?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="better-todo-warnings">Better TODO warnings</h2><p>If you're using warnings as TODO reminders, they might be mixing up with real warnings from the compiler. A little productivity tip: adding an emoji to the warnings, and using code snippets makes leaving and viewing TODO-warnings much nicer.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/Jeehut/status/1567849506682568705?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="refactoring-a-complex-view">Refactoring a complex View</h2><p>A short story on refactoring a complex SwiftUI view into smaller views that share the same view model instance. It's a nice approach to making the UI code more maintainable, and even testable.</p><h3 id="efficiently-develop-cleaner-swiftui-views-using-a-view-model"><a href="https://www.curiousalgorithm.com/post/efficiently-develop-cleaner-swiftui-views-using-a-view-model?ref=ioscodereview.com">Efficiently Develop Cleaner SwiftUI Views Using A View Model</a></h3><p>Learn how to quickly develop cleaner views by using a view model.</p><h2 id="initialization-in-swift">Initialization in Swift</h2><p>I learned Swift over the course of one summer, and this chapter on Initialization was what stuck with me the most.</p><p>Initialization is something we don't think too much about - you write your init method(s) and then if the compiler is not happy, do whatever Xcode suggests to fix it. But in reality, there are carefully thought-out rules and reasons behind restrictions being the way they are.</p><p>If you want to learn more about Swift itself, this is a nice read over a cup of something warm 🍁</p><h3 id="initialization-the-swift-programming-language-swift-5-7-"><a href="https://docs.swift.org/swift-book/LanguageGuide/Initialization.html?ref=ioscodereview.com">Initialization — The Swift Programming Language (Swift 5.7)</a></h3><p>Initialization is the process of preparing an instance of a class, structure, or enumeration for use.</p><h2 id="-featured-jobs">🧑‍💻 Featured jobs</h2><p>Proton (the company behind ProtonMail) has four open iOS positions: <a href="https://careers.proton.me/o/ios-engineer-vpn?ref=ioscodereview.com">iOS (VPN)</a>,<a href="https://careers.proton.me/o/ios-engineer-drive?ref=ioscodereview.com"> iOS (Drive)</a>,<a href="https://careers.proton.me/o/senior-ios-engineer-new-proton-product?ref=ioscodereview.com"> Senior iOS (new product)</a>, <a href="https://careers.proton.me/o/engineering-manager-ios-core?ref=ioscodereview.com">Engineering Manager (Core iOS)</a>. All are available remote and in-office.</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #32 ]]></title>
        <description><![CDATA[ Hi there!

Hope you&#39;re doing good and working toward your goals, whatever they are (whether that&#39;s work, resting more, spending more time with family, or protecting what&#39;s yours).

Today I have a couple of longer sections - hope you enjoy the read, and I& ]]></description>
        <link>https://ioscodereview.com/issues/32/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a591</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 22 Sep 2022 03:30:02 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there!</p><p>Hope you're doing good and working toward your goals, whatever they are (whether that's work, resting more, spending more time with family, or protecting what's yours).</p><p>Today I have a couple of longer sections - hope you enjoy the read, and I'm always curious to hear your thoughts!</p><p>Let's dive in 👇👇</p><hr><h2 id="is-it-swiftui-s-fault">Is it SwiftUI's fault?</h2><p>In the last couple of months there's been a lot of discourse on Twitter about the betas and the first public versions iOS 16/macOS 13. Some blame the rawness of the first versions specifically on SwiftUI and its immaturity, and this gets reverberated by others. Is it correct or even fair to blame incompleteness of features or bugs on one framework, disregarding other context such as processes, quality of QA, or time constraints?</p><p>I won't share the negative takes not to point fingers (I also don't have that many fingers 😂). Here's a few <em>other</em> takes on this, with a bonus positivity thread in the end. Tell me what you think!</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/fcbunn/status/1559564754561163264?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/fcbunn/status/913790160285917184?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1560560131481686016?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1560560524026613760?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/timroesner/status/1559570833261084673?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="swift-5-7-is-here-">Swift 5.7 is here!</h2><p>If you've already upgraded to Xcode 14, that means you can take advantage of improvements in Swift 5.7.</p><p>I might cover more individual features in the future, but in the meantime you can check out <a href="https://www.swift.org/blog/swift-language-updates-from-wwdc22/?ref=ioscodereview.com">the official overview</a> and <a href="https://www.swift.org/blog/swift-5.7-released/?ref=ioscodereview.com#swift-evolution-appendix">the full list of evolution proposals released in 5.7</a>.</p><p>Here's a thread about improvements to generics and protocols:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/slava_pestov/status/1533900187701223431?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>On the practical side of things, here's a regex to replace all <code>if let x = x {</code> with the new shorthand <code>if let x {</code>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/avielgr/status/1572260975746715648?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="compiler-errors-ftw">Compiler errors ftw</h2><p>Truth. Linters are also nice :)</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/basthomas/status/1570329087436013568?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="directory-of-apple-frameworks">Directory of Apple frameworks</h2><p>A full directory of all Apple frameworks with ability to filter by platform and minimal supported version 💪</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/MarcoEidinger/status/1572154850376179712?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Also I’d love to hear from you. Just reply to this email or DM at <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 👋</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #31 ]]></title>
        <description><![CDATA[ Hi there,

Did you enjoy the Apple event yesterday? Whether you&#39;re into the latest tech, or in the camp of anti-consumerism, hope you had a nice day 🙂

On Twitter it might seem that everyone is so excited about the new phones/watches/etc. But that&#39;s just ]]></description>
        <link>https://ioscodereview.com/issues/31/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a592</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 08 Sep 2022 03:50:25 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Did you enjoy the Apple event yesterday? Whether you're into the latest tech, or in the camp of anti-consumerism, hope you had a nice day 🙂</p><p>On Twitter it might seem that <em>everyone</em> is so excited about the new phones/watches/etc. But that's just the bubble. I, for one, will not be buying a new iPhone or watch any time soon - will keep enjoying my 2-year-old XS and series 5. To whomever needs to hear this, it's totally ok not to jump on buying the newest thing, but also it's ok to do so.</p><p>Now let's dive in, hope you learn something new today</p><hr><h2 id="on-weak-self-again-">On [weak] self (again)</h2><p>The weak self subject is a bit worn, but check this out. Steve has a good general point that such everyday things should be as ergonomic and effortless as possible in a language.</p><p>Here Steve also shared an article on the topic of self in closures. It's sort-of-a-reply to another opinionated piece, but I really like it on its own. If you were looking for once-and-for-all answer to the question of when to use <code>weak</code> and when not, this might be it.</p><p>I promise no more weak-self related tips 😀</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/stroughtonsmith/status/1515009921795997704?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h3 id="the-golden-rules-of-weak-self-chris-downie"><a href="https://chrisdownie.net/software/2022/04/10/the-golden-rules-of-weak-self/?ref=ioscodereview.com">The Golden Rules of weak self | Chris Downie</a></h3><p>Capturing self in a closure is a common thing to do in Swift, and one that hides a lot of nuance. Do you need to make it weak to avoid a reference cycle? Is making it weak all the time a problem?</p><h2 id="thoughts-on-massive-observable-objects">Thoughts on massive observable objects</h2><p>Having granular <code>ObservableObject</code>'s is a good way to go. To avoid unnecessary re-renders, give the high-level views only the dependencies they need.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/cwagdev/status/1506837668046401536?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/harlanhaskins/status/1555296150772535296?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="actions-in-environment">Actions in @Environment</h2><p>Very important TIL-moment if you're embracing <code>@Environment</code>-based action closures such as <code><a href="https://developer.apple.com/documentation/swiftui/openurlaction?ref=ioscodereview.com">OpenURLAction</a></code>. They should be callable types, not closures - otherwise views that use this variable will re-render unnecessarily whenever the environment <em>could</em> change - for example, on rotation or going to foreground.</p><p><a href="https://docs.swift.org/swift-book/ReferenceManual/Declarations.html?ref=ioscodereview.com#ID622">Callable structs</a> look like functions to the user of the api, as if you used a typealias for the closure type. If you define a type (struct, enum or class) and add a function named <code>func callAsFuntion()</code> , you'll then be able to invoke it by using <code>()</code> - <code>x()</code> is equivalent to <code>x.callAsFunction()</code>. This supports custom parameters too. It's a pretty cool feature in Swift!</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/lukeredpath/status/1491127803328495618?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/lukeredpath/status/1491127993032667136?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/lukeredpath/status/1491128201988689921?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/xavierjurado/status/1545470786097614849?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="slack-s-legacy-codebase-improvement-story">Slack's legacy codebase improvement story</h2><p>Recently Slack shared how they improve their legacy mobile codebase in a 3-article series. Here's an 8-minute summary, in case you don't have 30+ minutes to read the original, which is also linked there.</p><h3 id="mobile-app-refactoring-initiative-by-slack-by-elye"><a href="https://medium.com/mobile-app-development-publication/mobile-app-refactoring-initiative-by-slack-fedc4c4a6026?ref=ioscodereview.com">Mobile App Refactoring Initiative by Slack | by Elye</a></h3><p>A summary of how Slack stabilized, modularized, and modernized its mobile application code base</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #30 ]]></title>
        <description><![CDATA[ Hi there,

I hope the summer is treating you well, and you&#39;re progressing toward your goal, whatever it is!

As promised in the last issue, here&#39;s me sharing behind-the-scenes on how I make the newsletter issues: https://youtu.be/CgTqqkzeeh8

Let&#39;s dive in 👇


On ]]></description>
        <link>https://ioscodereview.com/issues/30/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a593</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 25 Aug 2022 04:13:00 -0700</pubDate>
        <media:content url="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/2023/03/ios-code-review-newsletter-header-2.png" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>I hope the summer is treating you well, and you're progressing toward your goal, whatever it is!</p><p>As promised in the last issue, here's me sharing behind-the-scenes on how I make the newsletter issues: <a href="https://youtu.be/CgTqqkzeeh8?ref=ioscodereview.com">https://youtu.be/CgTqqkzeeh8</a></p><p>Let's dive in 👇</p><hr><h2 id="on-push-notifications">On push notifications</h2><p>Last week Airbnb accidentally sent a test push notification to real users. Sarun has a good point - it's not a good idea to use inappropriate words in text that could be seen by users. This applies to everything - not just push text, but also in code that shouldn't theoretically be executed in non-debug builds.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/sarunw/status/1559871056873390083?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="the-sum-effort">The sum effort</h2><p>This simple formula Jane shared really put things in perspective for me.</p><p>Also it brought me to realise: if someone put effort into making the code more readable and well-structured, then it's less effort to read / work with later. If someone wrote "bad code" - perhaps spent less effort writing it - it takes extra effort to read later. Either way, the sum of total effort can be the same. No easy way out, the effort has to be spent by someone at some point, always.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/jevakallio/status/1531262225633222658?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="better-equality-test-failures">Better equality test failures</h2><p>If you've ever seen a test failure like this and hated it, <code><a href="https://github.com/krzysztofzablocki/Difference?ref=ioscodereview.com">Difference</a></code> is a package that can help. It offers a <code>diff</code> function that returns a readable explanation of what exactly is different. The doc for the library includes examples of how to easily use this with XCTest, Quick, and Composable Architecture.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/017/620/455/original/before.png" class="kg-image" alt loading="lazy"></figure><h3 id="github-krzysztofzablocki-difference"><a href="https://github.com/krzysztofzablocki/Difference?ref=ioscodereview.com">GitHub - krzysztofzablocki/Difference</a></h3><p>Simple way to identify what is different between 2 instances of any type. Must have for TDD.</p><h2 id="rest-api">REST API</h2><p>If you ever wondered what's the difference between just API and REST API, here's a short, digestible writeup about it:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/Rapid_API/status/1547204161485283329?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-code-duplication">On code duplication</h2><p>The problem of duplication is more nuanced than it seems. Common advice such as "duplication is cheaper than the wrong abstraction" is often based on the simplified view of the problem, that it's just about <em>code</em>.  In this article <a href="https://twitter.com/JasonSwett?ref=ioscodereview.com">@JasonSwett</a> looks at what duplication actually is, why it’s such a surprisingly complicated problem, and what can be done to address it. Thanks <a href="https://twitter.com/ctietze?ref=ioscodereview.com">@ctietze</a> for sharing the post!</p><blockquote>We could imagine that duplication could be defined as a piece of code that appears in two or more places. Indeed, this sounds like a very reasonable and accurate definition. But it’s actually wrong!</blockquote><blockquote><strong>Duplication is when there’s a single <em>behavior </em>that’s specified in two or more places</strong></blockquote><h3 id="duplication-code-with-jason"><a href="https://www.codewithjason.com/duplication/?ref=ioscodereview.com">Duplication - Code with Jason</a></h3><p>In this post I’ll show what duplication is, why it’s such a surprisingly complicated problem, and what can be done to address it.</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #29 ]]></title>
        <description><![CDATA[ Hi there,

As I&#39;m writing this, I am recording a show-and-tell video sharing a bit about my process creating this newsletter. I&#39;ll share it on Twitter and in the next issue, so stay tuned :)

I hope you find something interesting in my collection today 👇


Implicit weak ]]></description>
        <link>https://ioscodereview.com/issues/29/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a594</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 11 Aug 2022 03:30:02 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>As I'm writing this, I am recording a show-and-tell video sharing a bit about my process creating this newsletter. I'll share it on Twitter and in the next issue, so stay tuned :)</p><p>I hope you find something interesting in my collection today 👇</p><hr><h2 id="implicit-weak-self-is-coming">Implicit weak self is coming</h2><p>Usually I don't share things that Cannot Be Used Yet, but this one got me really excited! Starting with a future version of Swift, we won't have to write <code>self</code> inside closures after capturing it weakly:</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/017/384/113/original/screenshot_2022-08-11_at_00.53.36.png" class="kg-image" alt loading="lazy"></figure><h3 id="swift-evolution-0365-implicit-self-weak-capture-md-apple-swift-evolution-github"><a href="https://github.com/apple/swift-evolution/blob/main/proposals/0365-implicit-self-weak-capture.md?ref=ioscodereview.com">swift-evolution/0365-implicit-self-weak-capture.md · apple/swift-evolution · GitHub</a></h3><p>As of <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0269-implicit-self-explicit-capture.md?ref=ioscodereview.com">SE-0269</a>, implicit <code>self</code> is permitted in closures when <code>self</code> is written explicitly in the capture list. We should extend this support to <code>weak self</code> captures, and permit implicit <code>self</code> as long as <code>self</code> has been unwrapped.</p><h2 id="the-background-modifier">The background modifier</h2><p>In the past year the family of  <code>.background(...)</code> modifiers has evolved. Now it has a few versions, allowing to customise alignment, safe area ignoring behaviour, and shape style of the background. There's even a version without any parameters at all - it sets the background to a color fitting the current color scheme. All versions are <a href="https://developer.apple.com/documentation/swiftui/view/background(ignoressafeareaedges:)?ref=ioscodereview.com">listed here and are documented pretty well</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/thillsman/status/1549105316230488068?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="testing-the-mocks">Testing the mocks</h2><p>Stumbled onto a peculiar use-case for unit tests, and I've never seen it in real-life projects. Documenting mock behaviour via tests will often be seen as "too much", but it can come handy in cases when lots of tests rely on one mock.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dasdom/status/1556980686392889345?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1557046991640838147?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="thread-safety-in-swift">Thread safety in Swift</h2><p>A longer but worthy read about different ways to manage multithreading in Swift and their trade-offs.</p><h3 id="thread-safety-in-swift-1"><a href="https://swiftrocks.com/thread-safety-in-swift?ref=ioscodereview.com">Thread Safety in Swift</a></h3><p>Concurrency is the entry point for the most complicated and bizarre bugs a programmer will ever experience. In this article, I'll share my favorite methods of ensuring thread safety, as well as analyzing the performance of the different mechanisms.</p><h2 id="starting-with-open-source">Starting with open source</h2><p>If you want to contribute to a project but didn't know which one, here's a good collection:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/MarcoEidinger/status/1552990827642662918?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #28 ]]></title>
        <description><![CDATA[ Hi there,

I hope you find something useful or interesting in today&#39;s collection ✨


Live-updating cells

Starting with iOS 15, there&#39;s a set of reconfigure methods that let you update a cell that&#39;s already on-screen. This allows us to make nice animations to views inside ]]></description>
        <link>https://ioscodereview.com/issues/28/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a595</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 28 Jul 2022 04:12:02 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>I hope you find something useful or interesting in today's collection ✨</p><hr><h2 id="live-updating-cells">Live-updating cells</h2><p>Starting with iOS 15, there's a set of <code><a href="https://developer.apple.com/documentation/uikit/uitableview/3801923-reconfigurerows?ref=ioscodereview.com">reconfigure</a></code> methods that let you update a cell that's already on-screen. This allows us to make nice animations to views inside cells, which are not possible with <code>reloadData</code> - as it recreates cells from scratch.</p><p>In earlier iOS versions it was also possible to update existing cells, by getting on-screen cells with <code><a href="https://developer.apple.com/documentation/uikit/uitableview/1614983-cellforrow?ref=ioscodereview.com">UITableView.cellForRow(at:)</a></code> and updating the state manually. <code>reconfigure</code> can do that with less friction, and it can also update the height of the cell.</p><p>Check out Tyler's thread for a deeper dive into the new methods:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/smileyborg/status/1403908057185144832?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="approaches-to-mocking">Approaches to mocking</h2><p>Using the factory pattern is a common approach to mocking, but with Swift there are simpler approaches that work just as well: such as injecting values, injecting behaviour as closures (as opposed to injecting instances that perform a behaviour), or having factory methods as closures (as opposed to factory classes). In this thread Nick goes into different ways one can mock behaviour or values:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1547169053755805698?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>TL;DR:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1547169072097402881?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-code-readability">On code readability</h2><p>One comment from Nick's thread stood out to me - it really highlights the two extremes of code architecture: "hardcode everything" =&gt; no flexibility, changing one thing breaks other places; vs "mock everything" = code is not discoverable, no transparency in what to change code to achieve the goal. Balance is somewhere in the middle.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/da_vid_off/status/1547217008219013120?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="technical-debt-is-debt">Technical debt is debt</h2><p>Sometimes we say "there should be no technical debt". It's a really good aspiration, we've all been there. But as in life, going into debt can be beneficial:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/GergelyOrosz/status/1514116172454707200?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>but also:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/tlakomy/status/1547331578816303104?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="testing-codable-initializers">Testing Codable initializers</h2><p>A well-structured and understandable article on unit-testing custom Codable initializers. Lots of little gems in there - for one, <a href="https://github.com/krzysztofzablocki/Difference?ref=ioscodereview.com">the Difference library</a> looks like a huge quality-of-life improvements for unit tests.</p><h3 id="how-to-test-custom-codable-initializer-danijela-s-blog"><a href="https://danijelavrzan.com/posts/2022/07/how-to-test-custom-codable/?ref=ioscodereview.com">How to test custom Codable initializer | Danijela's blog</a></h3><p>Sometimes, when parsing a JSON, you need to implement a custom Codable initializer. Because of that custom logic, you're no longer using the default implementation. It's a good idea to test your code.</p><p>🤘☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below. If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #27 ]]></title>
        <description><![CDATA[ Hi there,

It&#39;s getting harder and harder to not share cool things from iOS 16 (that we can&#39;t yet use). I&#39;m managing to resist so far. Hope you find something interesting and useful in today&#39;s collection!

By the way, if you enjoy ]]></description>
        <link>https://ioscodereview.com/issues/27/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a596</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 14 Jul 2022 04:10:44 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>It's getting harder and harder to not share cool things from iOS 16 (that we can't yet use). I'm managing to resist so far. Hope you find something interesting and useful in today's collection!</p><p>By the way, if you enjoy reading the newsletter - send it to a colleague ☺️</p><hr><h2 id="using-unsafe-pointers-safely">Using unsafe pointers safely</h2><p>Unsafe pointers and bytes are only "safe" to use inside the body closure. From <code><a href="https://developer.apple.com/documentation/swift/withunsafemutablepointer(to:_:)?ref=ioscodereview.com">withUnsafeMutablePointer</a></code><a href="https://developer.apple.com/documentation/swift/withunsafemutablepointer(to:_:)?ref=ioscodereview.com"> documentation</a>: <code>The pointer argument is valid only for the duration of the function’s execution.</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/AirspeedSwift/status/1546760863599689728?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="dry-evolved">DRY, evolved</h2><p>Check out this thread about SPOT - <strong>Single Point Of Truth</strong> principle. It's similar to DRY (Don't Repeat Yourself), but better. I've been looking at code this way as long as I remember - I had no idea this way of thinking had its own name.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/adamgordonbell/status/1547249497872273409?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>This comment perfectly points out the difference between SPOT and DRY:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/NightWhistler/status/1547262343188566016?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="beautiful-rounded-corners">Beautiful rounded corners</h2><p>Are you using <code>cornerRadius</code> for rounding corners? There's a better way - <code>.clipShape</code> as a <code>RoundedRectangle</code> with <code>continuous</code> style in SwiftUI produces a smoother looking result. To achieve the same in UIKit, do <code>button.layer.cornerCurve = .continuous</code> .</p><p>Check this thread for comparison and SwiftUI code:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/vdbv/status/1531032275298750472?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="cloudkit">CloudKit</h2><p>In <a href="https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-21-1124111?ref=ioscodereview.com">issue #21</a> I shared an article about CloudKit being a red flag for indie developers. The biggest issue named was the inability to transfer the app to another developer account, if a CloudKit entitlement was ever used in the app.</p><p>That restriction is now gone - now apps that use iCloud can be transferred to another developer account 🎉</p><p>Here's the updated list of criteria for app transfer: <a href="https://help.apple.com/app-store-connect/?ref=ioscodereview.com#/devaf27784ff">App Transfer Criteria</a></p><h3 id="app-store-connect-update-releases-apple-developer"><a href="https://developer.apple.com/news/releases/?id=06152022a&ref=ioscodereview.com">App Store Connect Update - Releases - Apple Developer</a></h3><p>Apps that use iCloud can now be transferred to another developer in the Apple Developer Program.</p><h2 id="non-optional-core-data-attributes-in-swift">Non-optional Core Data attributes in Swift</h2><p>There is a distinction between the concept of optional and non-optional values in Swift and Core Data. In Swift, you get compile-time guarantees, but in Core Data, the framework is enforcing the model rules in run-time. Optional Core Data attributes should be optional properties in Swift, but what about non-optional attributes?</p><p>In this article Jesse shares a robust approach to handling the differences and making sure the app doesn't crash.</p><h3 id="how-to-more-gracefully-handle-non-optional-core-data-properties-in-swift-jesse-squires"><a href="https://www.jessesquires.com/blog/2022/01/26/core-data-optionals/?ref=ioscodereview.com">How to more gracefully handle non-optional Core Data properties in Swift · Jesse Squires</a></h3><p><br></p><p>🤘☀️☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below! If you enjoyed it, you can help grow the newsletter by spreading the word ☺️</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you - just reply to this email 👋</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #26 ]]></title>
        <description><![CDATA[ Hi there,

Every time I sit down to write an intro to an issue, I struggle between staying positive and the desire to address current events in the outside world. And every time I land on the decision to let this newsletter be a small island on the internet dedicated ]]></description>
        <link>https://ioscodereview.com/issues/26/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a597</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 30 Jun 2022 03:52:20 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Every time I sit down to write an intro to an issue, I struggle between staying positive and the desire to address current events in the outside world. And every time I land on the decision to let this newsletter be a small island on the internet dedicated to learning something new in the field we're passionate about.</p><p>If you are affected by war, the pandemic, or any of the other struggles in our crazy world - know that I think of you every time I write this 💛</p><p>And thanks to all of you for being loyal readers! Seeing the high open rates and receiving your feedback keeps my heart warm(-er) ☺️</p><p>So I hope you find something interesting in today's collection. Let's dive in?</p><hr><h2 id="accessible-custom-tab-bars">Accessible custom tab bars</h2><p><code><a href="https://developer.apple.com/documentation/uikit/uiaccessibilitytraits/1648592-tabbar?ref=ioscodereview.com">.tabBar</a></code> accessibility trait is almost magical when it comes to making a custom tab bar view behave like a system one.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dadederk/status/1542105711336951809?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>If you want to learn more about this, Bas Broek wrote a detailed article on implementing accessible custom tab bars:</p><h3 id="building-an-accessible-custom-tab-bar-bas-blog"><a href="https://www.basbroek.nl/custom-tab-bar-accessibility?ref=ioscodereview.com">Building an Accessible Custom Tab Bar | Bas’ Blog</a></h3><p>Recently, I’ve been working on making a custom tab bar in our app accessible. That is, make it work just like a native, out-of-the-box UITabBarController.</p><h2 id="interactive-image-preview-transition">Interactive image preview transition</h2><p>This is so cool. I didn't even realize that QuickLook framework can be used on iOS! Check out this short thread by Jordan:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/JordanMorgan10/status/1526999338928439296?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="sink">Sink</h2><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dvrzan/status/1522615963027488770?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="building-safe-apis">Building safe APIs</h2><p>The whole Swift language is <a href="https://developer.apple.com/swift/?ref=ioscodereview.com#safety">built upon safety principles</a>, so it only makes sense to apply them to our own APIs:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/rockbruno_/status/1526252822022524933?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="nspersistentcloudkitcontainer-trickiness">NSPersistentCloudKitContainer trickiness</h2><p>A comprehensive write up about the realities of using Core Data with CloudKit syncing. The article is a few months old, and just now it's been updated with new findings. So if you've seen it before - it's worth checking out again.</p><h3 id="general-findings-about-nspersistentcloudkitcontainer"><a href="https://crunchybagel.com/nspersistentcloudkitcontainer/?ref=ioscodereview.com">General Findings About NSPersistentCloudKitContainer</a></h3><p>This article contains our findings when converting Streaks to use NSPersistentCloudKitContainer.</p><p>🤘☮️</p><p>Alright, that’s it for today.</p><p>What do you think about me writing the comment <em>above</em> the tweet or link? Does it work? Or do you think it should be <em>after</em>? I'm curious to hear what you think. Let me know by replying to this email :)</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #25 ]]></title>
        <description><![CDATA[ Hi there,

Hope you had a wonderful WWDC week! I myself have been on vacation (and still am), and only checked out the keynote and saw some tweets from the community.

Other newsletters have featured lots of WWDC-related articles - for example I loved the latest iOS Dev Weekly which ]]></description>
        <link>https://ioscodereview.com/issues/25/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a598</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 16 Jun 2022 03:30:01 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope you had a wonderful WWDC week! I myself have been on vacation (and still am), and only checked out the keynote and saw some tweets from the community.</p><p>Other newsletters have featured lots of WWDC-related articles - for example I loved the latest <a href="https://iosdevweekly.com/?ref=ioscodereview.com">iOS Dev Weekly</a> which was 100% about WWDC.</p><p>I tend to forget all the new things by the time I can use them for real, so I'll be featuring more of the new APIs after Xcode 14 ships in September. My goal has always been to share things that can be used right away in real projects (gotta be honest it's also convenient because I could continue spending the vacation offline 😋)</p><p>I was also interviewed on the <a href="https://www.buzzsprout.com/1414396/10721946?ref=ioscodereview.com">AppForce1 podcast</a>, where I shared a bit about how I make the newsletter ☺️</p><p>Now let's dive in!</p><hr><h2 id="-unavailable-attribute">#unavailable attribute</h2><p>The new <code><a href="https://docs.swift.org/swift-book/ReferenceManual/Attributes.html?ref=ioscodereview.com">#unavailable</a></code> attribute has been added in Swift 5.6 (Xcode 13.3) - we can now check for older OS versions directly:</p><p><code>if #unavailable(iOS 15.0) { /* this code will run on iOS 14 and below */ }</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1486774836357652483?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="dealing-with-swiftui-type-inference">Dealing with SwiftUI type inference</h2><p>Do you sometimes try to write f.ex. <code>Color.background</code>, only to have nothing come up in autocomplete? The issue is that <code>.background</code> exists, just not on <code>Color</code> - it's a separate shape style, and the shorthand is only available by the magic of type inference. Jérôme here shares an approach for finding what you're looking for (see series of pictures in the full tweet)</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/jegnux/status/1491000100663042048?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="unit-tests-eh">Unit tests eh?</h2><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/tdinh_me/status/1519920418877952000?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>in all seriousness though:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/zet_manu/status/1510263282376101895?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/azamsharp/status/1512055836411105283?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="the-new-thing-is-out">The new thing is out</h2><p>Eternal wisdom from Jordan, now more relevant than ever before:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/JordanMorgan10/status/1510749975197761544?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="moving-the-cursor-in-terminal">Moving the cursor in terminal</h2><p>Okay this is not a code thing per se, but this terminal key binding has been a nice time saver for me since I learned it a couple of years ago:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/preshonyee/status/1511660537477799937?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #24 ]]></title>
        <description><![CDATA[ Hi there,

As promised, today&#39;s issue is a special one, and I&#39;m really excited to bring it to you. I wanted to spice things up a bit and invite a guest curator to create this issue. Because why not?

Say hi to Bas Broek - he ]]></description>
        <link>https://ioscodereview.com/issues/24/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a599</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 02 Jun 2022 03:41:20 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>As promised, today's issue is a special one, and I'm really excited to bring it to you. I wanted to spice things up a bit and invite a guest curator to create this issue. Because why not?</p><p>Say hi to <a href="https://twitter.com/basthomas?ref=ioscodereview.com">Bas Broek</a> - he will be curating the collection today. Bas had been authoring <a href="https://swiftweeklybrief.com/?ref=ioscodereview.com">Swift Weekly Brief (sadly discontinued)</a> for 2 years before joining the accessibility team at Apple. Now he's back to the community and shares his favourite bits of wisdom with us below 👇 😌</p><p>--------------------</p><p>This is Bas; I'm a friend of Marina's. As she reached out to me asking if I'd be up for writing an issue, I immediately said yes!</p><p>Having curated a newsletter before, I know it can be quite a bit of work; having the community help out was always a highlight of writing the newsletter, so I'm always happy to return that favor.</p><p>Enjoy!</p><hr><h2 id="accessibility-hints">Accessibility hints</h2><p>This thread is not about the literal API, but rather a bunch of things that are good to know and be aware of when building accessible products. I would love to know — how do you review code for accessibility?</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/RobRWAPP/status/1528351247702675461?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Speaking of accessibility hints, here's Dani sharing an insight every day for the WHOLE YEAR. So great to see this topic being put in the spotlight. Check out <a href="https://twitter.com/dadederk?ref=ioscodereview.com">his twitter</a> and/or follow him for the daily accessibility tips.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dadederk/status/1527318162861088768?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="attributed-strings">Attributed Strings</h2><p>As Marina mentioned in the last newsletter, it seems she's not the only one excited to see Natalia being back to blogging. Before she joined the SwiftUI team at Apple, her blog posts were a fresh breeze with amazing insights. Now, after leaving Apple, she's back to it, taking all the experience from her time at Apple with her — and it shows.</p><p>The new <code><a href="https://developer.apple.com/documentation/foundation/attributedstring?ref=ioscodereview.com">AttributedString</a></code> API is type-safe and powerful, and can be used not only in SwiftUI, but also with UIKit and AppKit. The type-inference going on is quite complex though. Check out the full article offering a deeper understanding on configuring the new attributed strings: <a href="https://nilcoalescing.com/blog/AttributedStringAttributeScopes/?ref=ioscodereview.com">AttributedString Attribute Scopes</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/natpanferova/status/1528633361341722624?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="equal-sizing-in-swiftui">Equal sizing in SwiftUI</h2><p>In this short article <a href="https://twitter.com/mcmaurberger?ref=ioscodereview.com">Matthias</a> shares a clean approach to making all elements in a <code>VStack</code> as wide as the widest element (but not take up the entire proposed width):</p><h3 id="swiftui-equal-and-ideal-sizes"><a href="https://sudrocket.de/blog/2022/05/swiftui-equal-and-ideal-sizes/?ref=ioscodereview.com">SwiftUI equal and ideal sizes</a></h3><p>One of the more common sentiments towards SwiftUI you’ll come across on the Internet goes something like this: It’s magical until it isn’t. Meaning: SwiftUI let’s you write UI code so quickly that it sometimes feels like a superpower. But suddenly you hit a wall and there’s seemingly no way around it. One example that illustrates this quite well is when you want to make all children of a VStack as wide as the widest child. Sounds like it should be straightforward. But it’s not. It’s a surprisingly hard problem.</p><h2 id="beyond-code">Beyond code</h2><p>Paris shares an insight on something we may overlook; sometimes it's not only about code.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/pxpgraphics/status/1529287600460161031?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="wwdc-preparation">WWDC Preparation</h2><p>Here's a couple of helpful tips on preparing for WWDC, when it comes to audits and labs:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/rjstelling/status/1531198192859205632?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twostraws/status/1531319533062959104?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Thanks for reading! Enjoy WWDC next week, and see you around!</p><p>- Bas</p><p>--------------------</p><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below.</p><p>Do you want to see other guest curators on the newsletter? Tell me who you'd like to hear from by replying to this email 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #23 ]]></title>
        <description><![CDATA[ Hi there,

WWDC is coming soon, are you excited? I am, but also looking forward to some vacation time. Not sure yet how much of catching up with the freshest-and-greatest content I&#39;ll do in June, but either way there will be some interesting stuff to share.

Also stay ]]></description>
        <link>https://ioscodereview.com/issues/23/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59a</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 19 May 2022 04:03:01 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>WWDC is coming soon, are you excited? I am, but also looking forward to some vacation time. Not sure yet how much of catching up with the freshest-and-greatest content I'll do in June, but either way there will be some interesting stuff to share.</p><p>Also stay tuned for the next issue #24 on June 1st, it will be a very special one 🤩</p><p>Now, let's dive in 👇</p><hr><h2 id="sizing-of-sf-symbols">Sizing of SF Symbols</h2><p>Great thread, nothing to add 😌 Excited to see that Natalia is back to blogging. She posts interesting content regularly, I wish I could feature all of it! Make sure to <a href="https://twitter.com/natpanferova?ref=ioscodereview.com">follow her on Twitter</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/natpanferova/status/1527171410392535041?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/natpanferova/status/1527171413601304576?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/jegnux/status/1527205230370234368?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/natpanferova/status/1527218791544786944?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="automating-the-encryption-compliance-check">Automating the encryption compliance check</h2><p>Definitely makes the life easier. For additional instructions check  <a href="https://developer.apple.com/documentation/security/complying_with_encryption_export_regulations?ref=ioscodereview.com">Complying with Encryption Export Regulations</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/danielpunkass/status/1517507834778370049?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="comparing-date-ranges">Comparing date ranges</h2><p>Since <code><a href="https://developer.apple.com/documentation/swift/closedrange/1784147-overlaps?ref=ioscodereview.com">overlaps(_:)</a></code> is declared on <code><a href="https://developer.apple.com/documentation/swift/range/?ref=ioscodereview.com">Range</a></code> and <code><a href="https://developer.apple.com/documentation/swift/closedrange?ref=ioscodereview.com">ClosedRange</a></code>, it can be useful not only for dates, along with <code><a href="https://developer.apple.com/documentation/swift/closedrange/1784630-contains?ref=ioscodereview.com">contains(_:)</a></code> (also found as the  <code><a href="https://developer.apple.com/documentation/swift/closedrange/2963623?ref=ioscodereview.com">~=</a></code> operator). One can almost forget about comparison operators 😀</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/peres/status/1516797470482776067?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-dependency-injection">On dependency injection</h2><p>Some food for thought on the topic of injecting / resolving dependencies. In this Twitter thread you'll find interesting points for and against various approaches 👇</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/simonbs/status/1521428389462253569?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/simonbs/status/1521440277239635969?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="starting-with-unit-testing">Starting with unit testing</h2><p>I wrote a guide to help developers who are motivated to start unit testing their code, but are uncertain about where to begin in practice. Among other things, you'll find some approaches to picking what to test, and how to start testing seemingly untestable code.</p><h3 id="unit-testing-the-pragmatic-guide-on-where-to-start-marina-gornostaeva"><a href="https://hybridcattt.com/blog/start-testing-pragmatic-guide/?ref=ioscodereview.com">Unit testing: The pragmatic guide on where to start | Marina Gornostaeva</a></h3><p><br></p><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #22 ]]></title>
        <description><![CDATA[ Hi there,

Hope you enjoy today&#39;s collection 🙌


Updating @State values

It&#39;s not safe to update @State properties from any callbacks except those provided by the SwiftUI framework. Always use View.onReceive(_:perform:) to react to external changes and update the view state. Below is the example ]]></description>
        <link>https://ioscodereview.com/issues/22/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59b</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 05 May 2022 03:51:40 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope you enjoy today's collection 🙌</p><hr><h2 id="updating-state-values">Updating @State values</h2><p>It's not safe to update <code><a href="https://developer.apple.com/documentation/swiftui/state?ref=ioscodereview.com">@State</a></code> properties from any callbacks except those provided by the SwiftUI framework. Always use <code><a href="https://developer.apple.com/documentation/swiftui/view/onreceive(_:perform:)?ref=ioscodereview.com">View.onReceive(_:perform:)</a></code> to react to external changes and update the view state. Below is the example of how to subscribe to <code>NotificationCenter</code> notifications:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/AlexBBrown/status/1466085295409938432?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/azamsharp/status/1465805517008392195?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="disabling-animation-on-a-view">Disabling animation on a View</h2><p><code><a href="https://developer.apple.com/documentation/swiftui/path/animation(_:)/?ref=ioscodereview.com">.animation(:_)</a></code> modifier was deprecated in iOS 15, so now to disable animations we should use <code><a href="https://developer.apple.com/documentation/swiftui/path/transaction(_:)/?ref=ioscodereview.com">.transaction(_:)</a></code> modifier that lets us customise the transition between two states. The doc says: "Use this modifier to change or replace the animation used in a view."</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1511697995628261379?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="foreach-vs-for">forEach vs for</h2><p>There are some things a <code>for</code> loop can do that <code>forEach</code> can't, and vice versa. <code>for</code> offers a more fine-grained control flow, allowing to exit early with <code>break</code>, as well as to iterate conditionally with <code>for ... where ...</code> . On the other hand,  <code>forEach</code> allows to pass closures to it. In most cases though it simply comes down to personal taste!</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/MarcoEidinger/status/1519226611085762561?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dev_jmitchell/status/1229826803365072896?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/AirspeedSwift/status/1511932638113656839?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>jk! <code>reduce</code> is nice sometimes.</p><h2 id="on-unnecessary-optimization">On (unnecessary) optimization</h2><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ds2001man/status/1516655307228909571?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="the-hidden-costs-of-your-dependencies">The Hidden Costs of Your Dependencies</h2><p>Ever had to argument why adding a third party dependency to the codebase does not come for free? Here's an amazing concise article summarizing all the different aspects:</p><h3 id="the-hidden-costs-of-your-dependencies-jason-zurita"><a href="https://jasonzurita.com/the-hidden-cost-of-dependencies/?ref=ioscodereview.com">The Hidden Costs of Your Dependencies | Jason Zurita</a></h3><p>Using a dependency isn’t always <em>bad</em>, but we should be intentional about how and when we use them and what the trade-offs are.</p><p>☮️💙💛</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #21 ]]></title>
        <description><![CDATA[ Hi there,

Hope you&#39;re safe, wherever you are. I&#39;m excited to share this week&#39;s findings with you!

This time I&#39;m doing something new in addition to the usual tips. The pandemic has been hash on the conference scene, and the next conference ]]></description>
        <link>https://ioscodereview.com/issues/21/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59c</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 21 Apr 2022 04:21:14 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope you're safe, wherever you are. I'm excited to share this week's findings with you!</p><p>This time I'm doing something new in addition to the usual tips. The pandemic has been hash on the conference scene, and the next conference season is coming up. I figured I'd highlight some conferences that are still looking for speakers.</p><p>Enjoy! ☀️</p><hr><h2 id="mainactor-run-vs-mainactor">MainActor.run vs @MainActor</h2><p>You can dispatch a <code>Task</code> to the main actor two ways - by explicitly calling <code>MainActor.run</code> or by annotating the closure with <code>@MainActor</code>. These two ways have different behaviour. If already on the main thread, the former will run immediately but the latter will run on the next runloop cycle. Find detailed explanation in <a href="https://www.hackingwithswift.com/quick-start/concurrency/how-to-use-mainactor-to-run-code-on-the-main-queue?ref=ioscodereview.com">this article by Paul Hudson</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1516431491042975744?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/lkuczborski/status/1516442306039230466?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="synchronizing-user-defaults">Synchronizing user defaults</h2><p>Since iOS 12, the <a href="https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize?ref=ioscodereview.com">synchronize()</a> method on <code>UserDefaults</code> <em>does nothing</em>, and we don't need to call it anymore. It's interesting that the method is not marked as deprecated yet. Here's a quote from the <a href="https://developer.apple.com/documentation/macos-release-notes/foundation-release-notes?ref=ioscodereview.com">release notes for iOS 12</a>:</p><blockquote>Removed synchronization requirements. It’s no longer necessary to use <code><a href="http://click.revue.email/ss/c/i4W3jH19ejJsNqtlezSpO1paC9hhp-ntpmEysO3iFvoDNTUrH3Bb1DZT_EuqZsN45cuMlnc0lJl2xCTRxZhpwhLOeqL9w_bWAnnCR2HcKs0Hy8-QjXBXLQsPlOM29VmCKiYu0JhhU3BBeV-2ebpW-nHEmFZAc93DgHuEaTLy5fgS3ENkTUq1xomBWyLNbtlJ87qr88s-PJaduZqnzIku4BAALxlkyUMDmp-1h1r6MbRCKas2jYjA492MCIDt1KCLcqTjk3KPMwrsU9VNKSPCTTQ3QRutQ4ZvPOUu-DWgqTJlPE2bVVkJE4sBJ7wMUiAR/3le/ZmUMCrasSJq325mVl5xxPw/h24/fDgrz6hQwUe2g1t1EXrTVb-IDRYbSMQVdUO4qPMLkGQ?ref=ioscodereview.com">synchronize()</a></code>, <code><a href="http://click.revue.email/ss/c/i4W3jH19ejJsNqtlezSpO1paC9hhp-ntpmEysO3iFvoDNTUrH3Bb1DZT_EuqZsN4GuPdCW-1MztyveWOWMm4O3yYPe_xG2Wei8xIbJq7TkOO4nKiuoVoEzItQPVE9nCysAwBxlQVeBOl_zdT_YGkW6rab_iRi5XxHB2QbStP7ve_OJNhrZdPYS8kxdS5T6GOm5Swp45pZq3OOUC-g5cqIfzTNmoJSJkgqwMa1J-w9cbe4WOMCCBYvriYHibrU5E8wNUYxUx1p_kPM4bRiWuKJ8aOy7hVafJwPIwjFsq-V5Fv6GVYBQ1618HOeWy0yt1W/3le/ZmUMCrasSJq325mVl5xxPw/h25/Twm_garnrXIHnOfeU-1T1RJ0OP4G4gCVoqPWOHpYAUA?ref=ioscodereview.com">CFPreferencesAppSynchronize(:)</a></code>, or <code><a href="http://click.revue.email/ss/c/i4W3jH19ejJsNqtlezSpO1paC9hhp-ntpmEysO3iFvoDNTUrH3Bb1DZT_EuqZsN4GuPdCW-1MztyveWOWMm4O20JRg_37Scw2wNZNdqiovnglXM5WhXfIdCZtXzdShp0k8yAjukAo9ihjS28MTrRvkEav_fbU4hgjE07gwewP0kw7su17Kf5Ej8O6NFTn5LiQTlPO4BEbkWFExCEOUHfMRw2TnpITd-lGP8c44nDUfa9hgLe0pgDslffKgd1mPeywdyvAMgA9PXHICQSc7Jmm9FYO8C62Q0eO1PQ1w3XM9x8LvdiJle1GmCy0fzFbXKo/3le/ZmUMCrasSJq325mVl5xxPw/h26/Gs6RBAzxCJYg07P6ijpNKqSlEHmibhlGaDvxB6kVyFE?ref=ioscodereview.com">CFPreferencesSynchronize(:::)</a></code>. These methods will be deprecated in a future version of the OS. Now that you don’t need to call these synchronization methods, the performance characteristics of <code><a href="http://click.revue.email/ss/c/i4W3jH19ejJsNqtlezSpO1paC9hhp-ntpmEysO3iFvoDNTUrH3Bb1DZT_EuqZsN45cuMlnc0lJl2xCTRxZhpwtuScJEBitDVdk1408Pr1BBGJ2iFw3yAcRYRpa-wFAiBXM5qXmysZ6m43H1GTN1K1LiFZhGgN8zjHj6aFYQxoVv05os9C2kv2LFmuQYA4xko5KCVyYsO2bW8OfNw2qgW0XaUT-WurWCyiLKUtXaB0ful4NzfXlVi9Ofwsbh_KKuRMQNhzOcKLdzGqth-dEJKxywI_Ma2rl1H4n-ek01r5cY/3le/ZmUMCrasSJq325mVl5xxPw/h27/Un-5M77BNxaD5jvgSmF7-PNUSG6a_gbWAXCQzYWrl9g?ref=ioscodereview.com">UserDefaults</a></code>and Preferences Utilities are slightly different: The time taken for enqueueing write operations is now paid by the writing thread, rather than by the next thread to call <code><a href="http://click.revue.email/ss/c/i4W3jH19ejJsNqtlezSpO1paC9hhp-ntpmEysO3iFvoDNTUrH3Bb1DZT_EuqZsN45cuMlnc0lJl2xCTRxZhpwhLOeqL9w_bWAnnCR2HcKs0Hy8-QjXBXLQsPlOM29VmCKiYu0JhhU3BBeV-2ebpW-nHEmFZAc93DgHuEaTLy5fgS3ENkTUq1xomBWyLNbtlJ87qr88s-PJaduZqnzIku4BAALxlkyUMDmp-1h1r6MbRCKas2jYjA492MCIDt1KCLcqTjk3KPMwrsU9VNKSPCTTQ3QRutQ4ZvPOUu-DWgqTJlPE2bVVkJE4sBJ7wMUiAR/3le/ZmUMCrasSJq325mVl5xxPw/h28/uwjzeBb3ejd1r1BVKX7ge8lumjNpVyFhu2DfkaJLPaI?ref=ioscodereview.com">synchronize()</a></code> or do a read operation.</blockquote><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/JordanMorgan10/status/1516832320887656457?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="codable-in-firebase">Codable in Firebase</h2><p>There's now built-in <code>Codable</code> support in Firebase, so there's no need to bring in additional packages such as <code><a href="https://github.com/alickbass/CodableFirebase?ref=ioscodereview.com">CodableFirebase</a></code>. Now you can simply write: <code>ref.getDocument(as: Book.self) {...}.</code> The type just needs to have a property annotated with <code>@DocumentID</code> property wrapper, so the framework knows which property is the identifier. If you want to learn more, Peter also wrote a <a href="https://peterfriese.dev/posts/firestore-codable-the-comprehensive-guide/?ref=ioscodereview.com">comprehensive guide</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/peterfriese/status/1507356658707619850?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-refactoring">On refactoring</h2><p>Wise words here. If one commit contains both refactoring and behaviour change, if things break (or, <em>when</em>) it'll be hard to tell whether they broke due to refactoring or due to a bug in new behaviour. I split these up, always.</p><p>Also sometimes people call any change in code structure <em>a refactoring</em>. Here's a quote from <a href="https://en.wikipedia.org/wiki/Code_refactoring?ref=ioscodereview.com">Wikipedia</a>: "code refactoring is the process of restructuring existing computer code—changing the <em>factoring</em>—without changing its external behavior."</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/acdlite/status/1512135917393301506?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="cloudkit">CloudKit</h2><p>Did you know that apps using iCloud (CloudKit) cannot be transferred to another account? This means that selling an app with CloudKit can be a tricky endeavour - with the only option being to sell the whole developer account.</p><h3 id="icloud-red-flag-for-indie-developers"><a href="https://jknlsn.com/posts/2022-03-24-icloud-redflag-for-indie-developers?ref=ioscodereview.com">iCloud red flag for indie developers</a></h3><p>As a consumer, I love iCloud. One central storage for documents, photos and app data. What's not to love? As a developer, I'm much more wary.</p><h2 id="conference-time-">Conference time!</h2><p>This time I want to help the community by highlighting some of the upcoming conferences.</p><p>CFP (call for papers) is a format when potential speakers submit their talk ideas. If you've been dreaming about giving a talk - this is your hint to finally go for it 🤘</p><h3 id="looking-for-speakers">Looking for speakers</h3><ul><li><strong>iOSDevUK</strong>, Aberystwyth, UK, 5-8 September 2022. <a href="https://www.iosdevuk.com/speakercall-1.?ref=ioscodereview.com">https://www.iosdevuk.com/speakercall-1.</a> They're looking for speakers from underrepresented groups.</li><li><strong>SwiftLeeds</strong>, Leeds, UK, 20 October 2022. <a href="https://swiftleeds.co.uk/?ref=ioscodereview.com">https://swiftleeds.co.uk/</a></li><li><strong>360idev</strong>, Denver, US, 28-31 Aug 2022. <a href="https://360idev.com/call-for-papers/?ref=ioscodereview.com">https://360idev.com/call-for-papers/</a></li><li><strong>SwiftConf</strong>, Cologne, Germany, Aug 17-18, 2022. <a href="https://swiftconf.com/?ref=ioscodereview.com">https://swiftconf.com</a></li></ul><h3 id="new-kid-on-the-block">New kid on the block</h3><ul><li><strong>plSwift </strong>- A brand-new Swift/iOS conference in Wrocław, Poland. 25-26 May 2022. <a href="https://t.co/0DVLmRHxsr?ref=ioscodereview.com">plswift.com</a></li></ul><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #20 ]]></title>
        <description><![CDATA[ Hi there,

Can&#39;t believe this is already the 20th issue  🎉 A milestone for sure. Thank you for your continuous support and feedback - and for spreading the word!


Old new UIKit APIs

When new APIs are introduced at WWDC, we can&#39;t use them right away in ]]></description>
        <link>https://ioscodereview.com/issues/20/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59d</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 07 Apr 2022 03:47:31 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Can't believe this is already the 20th issue  🎉 A milestone for sure. Thank you for your continuous support and feedback - and for spreading the word!</p><hr><h2 id="old-new-uikit-apis">Old new UIKit APIs</h2><p>When new APIs are introduced at WWDC, we can't use them right away in apps supporting previous iOS versions. And when the time comes, we already forgot about them.</p><p><strong>@onmyway133</strong> shares a collection of reminders about cool and useful APIs that were introduced in previous years:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1511358074367328258?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Here's a link to <code><a href="https://developer.apple.com/documentation/uikit/uiviewpropertyanimator?ref=ioscodereview.com">UIViewPropertyAnimator documentation</a></code>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1511358087839375362?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p><a href="https://developer.apple.com/documentation/uikit/uistackview/2866023-setcustomspacing?ref=ioscodereview.com">Documentation for </a><code><a href="https://developer.apple.com/documentation/uikit/uistackview/2866023-setcustomspacing?ref=ioscodereview.com">setCustomSpacing(_:after:)</a></code> - alas, not very useful.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1511358100598448130?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Here's a link to <code><a href="https://developer.apple.com/documentation/uikit/uitextcontenttype?ref=ioscodereview.com">UITextContentType documentation</a></code>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1511358112552284163?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Some useful links: <code><a href="https://developer.apple.com/documentation/uikit/uitabbaritemappearance?ref=ioscodereview.com">UITabBarItemAppearance documentation</a></code>, <code><a href="https://developer.apple.com/documentation/uikit/uitabbarappearance?ref=ioscodereview.com">UITabBarAppearance documentation</a></code>, <a href="https://emptytheory.com/2019/12/31/using-uitabbarappearance-for-tab-bar-changes-in-ios-13/?ref=ioscodereview.com">Using UITabBarAppearance for Tab Bar changes in iOS 13</a>.  Similar API is available for navigation bars: <code><a href="https://developer.apple.com/documentation/uikit/uinavigationbarappearance?ref=ioscodereview.com">UINavigationBarAppearance documentation</a></code>, <a href="https://sarunw.com/posts/uinavigationbar-changes-in-ios13/?ref=ioscodereview.com">UINavigationBar changes in iOS 13</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/onmyway133/status/1511358040284442625?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Here's a link to <code><a href="https://developer.apple.com/documentation/uikit/uiscrollview/keyboarddismissmode?ref=ioscodereview.com">KeyboardDismissMode documentation</a></code>.</p><h2 id="array-slice-indices">Array slice indices</h2><p>The fact that a slice is just a "view" into the original array can be unexpected and lead to indexing bugs. Convert to the slice to <code>Array(slice)</code> to avoid this, though then new memory will be used.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/DrCarleeknikov/status/1511108710889758721?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="int-vs-uint">Int vs UInt</h2><p>Turns out, <a href="https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html?ref=ioscodereview.com">the official Swift documentation</a> recommends against using <code>UInt</code> for simply noting values that shouldn't be negative:</p><blockquote>A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference.</blockquote><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/GilroyBen/status/1317081098195734528?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-software-design">On software design</h2><p>Have you heard of the broken windows theory? In short, it says that when there's a broken window on a building, more windows will get broken there. One graffiti attracts more graffiti. This is a fairly short article, that nonetheless brings an interesting perspective to the topic of software design and maintenance.</p><h3 id="apply-broken-windows-theory-to-the-software-design"><a href="https://www.offnotes.org/apply-broken-windows-theory-to-the-software-design/?ref=ioscodereview.com">Apply "Broken-Windows" theory to the Software Design</a></h3><p>"Broken Windows" is one of the most cited articles in the history of criminology. What can it teach in the world of software development?</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #19 ]]></title>
        <description><![CDATA[ Hi there,

The world is still a mess, but I&#39;m really excited to bring you some learnings today. Enjoy! 🙌


The Code Review Pyramid

What to look at in a code review? Check out this infographic shared by @gunnarmorling. Also available on the blog: The Code Review Pyramid







Struct ]]></description>
        <link>https://ioscodereview.com/issues/19/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59e</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 24 Mar 2022 04:50:04 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>The world is still a mess, but I'm really excited to bring you some learnings today. Enjoy! 🙌</p><hr><h2 id="the-code-review-pyramid">The Code Review Pyramid</h2><p>What to look at in a code review? Check out this infographic shared by <strong>@gunnarmorling</strong>. Also available on the blog: <a href="https://www.morling.dev/blog/the-code-review-pyramid/?ref=ioscodereview.com">The Code Review Pyramid</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/gunnarmorling/status/1501645187407388679?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="struct-properties-var-or-let">Struct properties - var or let?</h2><p>Found this conversation thread on pros and cons of making properties in structs  <code>var</code> vs <code>let</code>. I like the take by <strong>@myell0w</strong>, and you'll find even more opinions in the thread.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mluisbrown/status/1320798726735187968?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mluisbrown/status/1320802409271205888?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/myell0w/status/1320807408390807553?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="decoding-corrupted-arrays-with-codable">Decoding corrupted arrays with Codable</h2><p>By default, decoding an array of <code>Codable</code> will fail if one of the elements fails to decode. That's not obvious behaviour - and it's not always desirable.</p><p>The common way to solve this is to decode as an array of wrapper objects where the model is optional, and <code>compactMap</code> it after. For concrete implementation details, check out the article:</p><h3 id="decode-an-array-with-a-corrupted-element-sarunw"><a href="https://sarunw.com/posts/decode-array-with-corrupted-element/?ref=ioscodereview.com">Decode an array with a corrupted element | Sarunw</a></h3><p>When working with an unstable, legacy, or third party API, you might get a malformed object in an array. Learn how to decode a JSON array with corrupted data in Codable safely.</p><h2 id="fixing-swiftui-preview-pausing">Fixing SwiftUI preview pausing</h2><p>Turns out, structure of the code affects how SwiftUI previews are functioning. For example, changing the default value of a property will pause previews, but if the property is computed - changing the body won't pause previews.</p><p>This is because live reloading is implemented using <code>@_dynamicReplacement</code> attribute, which only supports replacing <em>bodies</em> of functions and properties. If you want to learn even more details, check out this article I wrote 2 months ago and forgot to include earlier 😀</p><h3 id="fixing-swiftui-s-automatic-preview-updating-paused-marina-gornostaeva"><a href="https://hybridcattt.com/blog/fixing-swiftui-previews/?ref=ioscodereview.com">Fixing SwiftUI’s Automatic Preview Updating Paused | Marina Gornostaeva</a></h3><p>Understand why SwiftUI previews keep getting paused and how to improve the situation</p><h2 id="a-refactoring-story">A refactoring story</h2><p>An entertaining and educational read about refactoring of a complex app. Good with a cup of tea 🍵</p><h3 id="refactoring-uber-s-rider-app-space-is-disorienting"><a href="http://spaceisdisorienting.com/refactoring-the-uber-rider-app?ref=ioscodereview.com">Refactoring Uber's Rider app • Space is Disorienting</a></h3><p>There was a lot of discussion at the end of 2020 about Uber’s mobile apps. Many wondered aloud why we didn’t just refactor the app instead of rewriting it. I thought I’d add some context into where things were <em>prior</em> to the rewrite.</p><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #18 ]]></title>
        <description><![CDATA[ Hi there,

I hope you enjoy today&#39;s content. Let&#39;s dive in 👇


Documenting app&#39;s footprint

Here&#39;s an interesting thread where people share how they document where the app saves things and how they like to organise constants. Lots of opinions - some prefer ]]></description>
        <link>https://ioscodereview.com/issues/18/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a59f</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 10 Mar 2022 03:47:29 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>I hope you enjoy today's content. Let's dive in 👇</p><hr><h2 id="documenting-app-s-footprint">Documenting app's footprint</h2><p>Here's an interesting thread where people share how they document where the app saves things and how they like to organise constants. Lots of opinions - some prefer enums, others prefer extensions on <code>UserDefaults</code>. I personally like to use enums as shown in this tweet - making one per-app or per-module depending on the size of the codebase.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1495704348743057414?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="named-loops">Named loops</h2><p>If you have nested loops, you can label them, and use the label as part of your <code>break</code> or <code>continue</code> statements. This also works for <code>if</code>, <code>switch</code>, <code>do</code> statements. Here's an article with more detailed examples: <a href="https://andybargh.com/break-and-continue/?ref=ioscodereview.com">Swift’s Break and Continue Statements by Andy Bargh</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/zet_manu/status/1498324614346276866?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="text-or-string">Text or String?</h2><p>If you also get tired of wrapping strings in <code>Text</code> all the time, here's a tiny extension to make it easier:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/blazs/status/1500415081116581888?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="some-wise-words">Some wise words</h2><p>I concur:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mdiep/status/1471600882844319765?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-passing-app-store-review">On passing App Store review</h2><p>This one is not about improving the code, but improving the release cycle of the app. In this thread <strong>@jordibruin</strong> shares how he organises his App Store review submissions to minimise chances of getting rejected. Such wonderful advice that I couldn't not share!</p><p>He explains what he writes in the messages, attachments he makes, and most interestingly about his FAQ page he shares with the review team.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/jordibruin/status/1471081934684147716?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>☮️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #17 ]]></title>
        <description><![CDATA[ I spent the whole morning thinking about whether it&#39;s appropriate to send out an issue today. For the sake of consistency I decided in favour of delivering on the promise of code improvement tips in your inbox every two weeks.

This time I got no cheerful words though. ]]></description>
        <link>https://ioscodereview.com/issues/17/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a0</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 24 Feb 2022 03:04:06 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>I spent the whole morning thinking about whether it's appropriate to send out an issue today. For the sake of consistency I decided in favour of delivering on the promise of code improvement tips in your inbox every two weeks.</p><p>This time I got no cheerful words though. If you're able to enjoy something today - I hope you enjoy these tips.</p><hr><h2 id="uninitialized-variables-defer-">Uninitialized variables + defer = 👯‍♀️</h2><p>One of my favourite combinations of Swift's features:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nunovieira_dev/status/1487265828227764225?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="httpserver-or-httpserver">HttpServer or HTTPServer?</h2><p><a href="https://swift.org/documentation/api-design-guidelines/?ref=ioscodereview.com">Swift API design guidelines</a> have the answer:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/fabianfett/status/1489160450004733957?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="representing-measurement-units">Representing measurement units</h2><p><code><a href="https://developer.apple.com/documentation/foundation/measurement?ref=ioscodereview.com">Measurement</a></code> is a type that represents a numeric quantity labeled with a unit of measure, with support for unit conversion and unit-aware calculations. <code><a href="https://developer.apple.com/documentation/foundation/measurementformatter?ref=ioscodereview.com">MeasurementFormatter</a></code> has a range of options for presenting measurements in a localised way. Both are available since iOS 10. Starting iOS 15, SwiftUI's <code>Text</code> supports measurement formatting too:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/BigMtnStudio/status/1494223870408208384?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="the-missing-swiftui-docs">The missing SwiftUI docs</h2><p>Community-made documentation for SwiftUI types with beautiful examples. For instance, check out <code><a href="https://swiftontap.com/tabview?ref=ioscodereview.com">TabView</a></code><a href="https://swiftontap.com/tabview?ref=ioscodereview.com"> documentation</a> to get a taste.</p><h3 id="swiftontap"><a href="https://swiftontap.com/?ref=ioscodereview.com">SwiftOnTap</a></h3><p>SwiftUI fully documented, with visual examples on every page.</p><h2 id="is-there-the-best-architecture">Is there the best architecture?</h2><p>What works for a tiny startup won't work for a mature product with a large dev team, and vice versa. It's obvious, but still worth remembering when we discuss architectures in abstract.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/peres/status/1470754984304250882?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>☮️</p><p>Alright, that’s it for today.</p><p>Wherever you are, I hope you're safe.</p><p>I’d love to hear from you - reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #16 ]]></title>
        <description><![CDATA[ Hi there,

This time I have exciting news to share - last week we crossed the 1000 subscribers mark 🥳 It&#39;s so honouring to be able to share the learnings with such a wide community from all around the world. Thank you for tuning in!

And now, let&#39; ]]></description>
        <link>https://ioscodereview.com/issues/16/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a1</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 10 Feb 2022 03:16:37 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>This time I have exciting news to share - last week we crossed the 1000 subscribers mark 🥳 It's so honouring to be able to share the learnings with such a wide community from all around the world. Thank you for tuning in!</p><p>And now, let's dive into the tips 👇</p><hr><h2 id="managing-image-assets">Managing image assets</h2><p>This is 100% my favourite way to organise assets - images or SF symbols, and even localisation strings.</p><p>The best part is that you can easily check in unit tests that none of the assets are missing (or misspelled). Just conform your enum to <code>CaseIterable</code> and test:</p><p><code>Asset.allCases.forEach { ﻿XCTAssertNotNil($0.image, "\($0) is missing") }</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/iSapozhnik/status/1490300632686862338?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="use-labels-in-swiftui">Use Labels in SwiftUI</h2><p>Here's a nice short summary of benefits of using <code>Label</code> over just an <code>HStack</code> with <code>Image</code> and <code>Text</code>. I think we should always prefer <code>Label</code>. More details and examples in <a href="https://developer.apple.com/documentation/swiftui/label?ref=ioscodereview.com">the documentation</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/Code_Bender/status/1465820393424531462?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-counting-characters">On counting characters</h2><p><a href="https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-9-789293?ref=ioscodereview.com">Few issues ago</a> I wrote about being careful not to mix ranges from <code>String</code> and <code>NSString</code>. And here's a graphic example of how just a simple emoji is counted differently, with explanation why:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/krzyzanowskim/status/1491042128499253249?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/TheCodeLorax/status/1491070795950731264?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-pure-functions">On pure functions</h2><p>This is a great approach to structuring code, and it pairs well with the concept of <a href="https://twitter.com/danielemargutti/status/1490592233690644486?s=20&t=l3O937-2uS5UWzu0HzQUpQ&ref=ioscodereview.com">pure functions</a>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/danielemargutti/status/1490592233690644486?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="visual-logging">Visual logging</h2><p>I started using emojis in logs only recently, and it's life changing on large projects. For log levels, or just easily finding that one print statement you just added.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/parrots/status/1486731248420593686?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="memory-management-with-async-await">Memory management with async/await</h2><p>This article was widely shared so you may have already seen it, but if not - definitely check it out if you're already using concurrency. The biggest takeaway: we have to remember to cancel forever-running observations, such as <code>for await x in in publisher {...}</code>.</p><h3 id="memory-management-when-using-async-await-in-swift-swift-by-sundell"><a href="https://swiftbysundell.com/articles/memory-management-when-using-async-await/?ref=ioscodereview.com">Memory management when using async/await in Swift | Swift by Sundell</a></h3><p>Managing an app’s memory is something that tends to be especially tricky when it comes to asynchronous code, so let’s take a look at how to do just that when using async/await.</p><p>🤘</p><p>Alright, that’s it for today.</p><p>I have a question for you: I'm sending this newsletter around lunch time in the European timezone. How has your experience been with that? Share your thoughts by replying to this email or by pressing the buttons below.</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #15 ]]></title>
        <description><![CDATA[ Hi there,

Hope your Thursday is going the way you want it to go 🌟 Let&#39;s dive into this week&#39;s highlights!


On mixing Swift and ObjC

Adding a shim layer is a great way to approach moving to Swift in an Objective-C codebase. I can confirm from ]]></description>
        <link>https://ioscodereview.com/issues/15/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a2</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 27 Jan 2022 03:57:44 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🌟 Let's dive into this week's highlights!</p><hr><h2 id="on-mixing-swift-and-objc">On mixing Swift and ObjC</h2><p>Adding a shim layer is a great way to approach moving to Swift in an Objective-C codebase. I can confirm from hands-on experience practicing it successfully on large ObjC projects.</p><p>I had this tweet saved in bookmarks for a while, thinking maybe I'll write an article on it some day. But no need anymore - Steve himself just published a great article going deeper on this topic. Huzza! Here's the full article: <a href="https://www.steveonstuff.com/2022/01/13/migrating-from-objc-to-swift.html?ref=ioscodereview.com">An Approach for Migrating From Objective-C to Swift</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/SteveBarnegren/status/1322342727120523266?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="golden-path">Golden path</h2><p><a href="https://en.wikipedia.org/wiki/Happy_path?ref=ioscodereview.com">Wikipedia describes</a> golden (happy) path as a default scenario featuring no exceptional or error conditions. Swift sure took it to heart by introducing the <code>guard</code> statement. If you are not using it actively yet, maybe this is your sign 😀</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/TheCodingArt/status/1481273053237723138?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/greg_ellis/status/1478382971820417031?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="-discardableresult">@discardableResult</h2><p><code>@discardableResult</code> is the proper way to silence the unused variable warning:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/BarekJaafar/status/1483577815253532676?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="lazy-variables-are-not-thread-safe">Lazy variables are not thread safe</h2><p>Antoine explains how to avoid data races with lazy variables in this section: <a href="https://www.avanderlee.com/swift/thread-sanitizer-data-races/?ref=ioscodereview.com#how-to-solve-a-data-race">How to solve a data race</a>. TL;DR: you can either make all operations with the variable on the same thread, or use actors - the new feature in Swift.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1480553967063126027?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="spell-check-in-comments">Spell check in comments</h2><p>Did you know that Xcode has a built-in spellchecker for comments? That's been introduced in Xcode 11. I think it's strange that it's not enabled by default. <strong>@felibe444</strong> wrote a quick guide on how to turn it on: <a href="https://fbernutz.github.io/posts/2022-01-23-spelling-grammar-in-xcode/?ref=ioscodereview.com">Typos in Xcode – Never Again!</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/felibe444/status/1485231971890601990?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="hig-for-text">HIG for text</h2><p>Made by <a href="https://twitter.com/k_katsumi?ref=ioscodereview.com">@k_katsumi</a>, Apple Localization Terms Glossary is a handy reference point for text in your app. You can easily refer to texts that Apple uses in their UI, as well as see corresponding localisations to other languages.</p><p>Another great resource in this area is Apple Style Guide, the official glossary of how to use certain terms. It's like Human Interface Guidelines but for text - definitely worth checking out.</p><h3 id="apple-localization-terms-glossary"><a href="https://applelocalization.com/?ref=ioscodereview.com">Apple Localization Terms Glossary</a></h3><p>An unofficial Apple localization terms glossary that allows you to search for standard localization texts provided by the Apple platform.</p><h3 id="-apple-style-guide-on-apple-books"><a href="https://books.apple.com/book/id1161855204?ref=ioscodereview.com">‎Apple Style Guide on Apple Books</a></h3><p>This book provides editorial guidelines for text in Apple materials. Apple developers and third-party developers should follow this guide for customer-facing text.</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #14 ]]></title>
        <description><![CDATA[ Hi there,

Welcome to the first issue of 2022! ☀️

Hope everyone had lovely holidays. I did, and am pumped to jump back into sharing tips regularly. Enjoy!


On counting words

There are multiple problems with splitting words by punctuation and whitespace - even in English &quot;shouldn&#39;t&quot; ]]></description>
        <link>https://ioscodereview.com/issues/14/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a3</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 13 Jan 2022 04:22:06 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Welcome to the first issue of 2022! ☀️</p><p>Hope everyone had lovely holidays. I did, and am pumped to jump back into sharing tips regularly. Enjoy!</p><hr><h2 id="on-counting-words">On counting words</h2><p>There are multiple problems with splitting words by punctuation and whitespace - even in English "shouldn't" would split into two 'words'. And some languages don't even have spaces. Full article: <a href="https://medium.com/@sorenlind/three-ways-to-enumerate-the-words-in-a-string-using-swift-7da5504f0062?ref=ioscodereview.com">Three Ways to Enumerate the Words In a String Using Swift</a> by <a href="https://twitter.com/sorenlind?ref=ioscodereview.com">@sorenlind</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/SufiyanYasa/status/1480149173424910336?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="working-with-years-in-dates">Working with years in dates</h2><p>Are you using <code>YYYY</code> or <code>yyyy</code> in your date formats? <code>YYYY</code> represents <em>week year</em> which is the same as calendar year most of the time, but isn't for some dates at the end of December. So there's plenty of time to fix it 😀 Good resources on this:</p><p><a href="https://nsdateformatter.com/?ref=ioscodereview.com">https://nsdateformatter.com</a> to quickly test different formats. This site also has a nice documentation page where you can get a refresher on which APIs to use when. Or check out <a href="http://unicode.org/reports/tr35/tr35-31/tr35-dates.html?ref=ioscodereview.com#Date_Format_Patterns">the official Unicode documentation</a> if you want to get to the original.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/VishalMalvi_/status/1475835430067052546?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="custom-date-formats-localized">Custom date formats, localized</h2><p>Setting <code>DateFormatter</code>'s <code><a href="https://developer.apple.com/documentation/foundation/dateformatter/1415411-datestyle?ref=ioscodereview.com">dateStyle</a></code> and <code><a href="https://developer.apple.com/documentation/foundation/dateformatter/1413467-timestyle?ref=ioscodereview.com">timeStyle</a></code>  result in it producing localised strings. To get a custom set of date components as a localised string, we can use <code><a href="https://developer.apple.com/documentation/foundation/dateformatter/1417087-setlocalizeddateformatfromtempla?ref=ioscodereview.com">setLocalizedDateFormatFromTemplate(_:)</a></code>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/DonnyWals/status/1316703536407818241?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="learnings-from-swiftui-apis">Learnings from SwiftUI APIs</h2><p>This is how you set a custom title view in the navigation bar in SwiftUI. How would one ever guess that this is how it should be done? <code><a href="https://developer.apple.com/documentation/swiftui/toolbaritemplacement/principal?ref=ioscodereview.com">ToolbarItemPlacement.principal</a></code>  has a small paragraph about its effect. In my opinion, this API is not discoverable at all. (thanks <strong>@sarunw</strong> for sharing this!)</p><p>Two learnings here: 1) SwiftUI is still cool and powerful, you can do so much with so little code 2) With great flexibility of API, the understandability can take a hit. Because it will behave differently in different contexts and different platforms, SwiftUI has to use overly generic terms such as 'toolbar' or 'principal placement'. So users have to resort to documentation for understanding what it even means. This is a big tradeoff and something to keep in mind when designing our own API.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/sarunw/status/1480983729942192132?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="storekit-resources">StoreKit resources</h2><p>Stumbled onto two repos with comprehensive information on working with StoreKit APIs. There is a repo for StoreKit 2 (new in iOS 15) and a repo for the good old StoreKit. If you're looking to implement in-app purchases from scratch, these are great as reference after checking the official Apple documentation.</p><p>Both repos have a mile-long readme with every little detail covered, as well as working code that covers every edge case - unlike the official samples provided by Apple. Made by <a href="https://twitter.com/archer_russel?ref=ioscodereview.com">@archer_russel</a></p><h3 id="github-russell-archer-storehelper"><a href="https://github.com/russell-archer/StoreHelper?ref=ioscodereview.com">GitHub - russell-archer/StoreHelper</a></h3><p>Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5 and iOS 15.</p><h3 id="github-russell-archer-iapdemo"><a href="https://github.com/russell-archer/IAPDemo?ref=ioscodereview.com">GitHub - russell-archer/IAPDemo</a></h3><p>Implementing and testing In-App Purchases in Xcode 12 and iOS 14, including local receipt validation.</p><h2 id="review-prs-in-ide-form">Review PRs in IDE form</h2><p>Did you know that you can review PRs in Github in a full-blown IDE right in the browser? I find it more convenient, being able to navigate between files and having extra code highlighting. You can even make edits. Inline PR discussions are included. Press `.` (dot) while on the PR page, or change the url from GitHub.com to GitHub.dev.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/013/514/068/original/github.png" class="kg-image" alt loading="lazy"><figcaption>VS Code in the browser</figcaption></figure><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Simply reply to this email, or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #13 ]]></title>
        <description><![CDATA[ Hi there,

Welcome to the 13th issue, the last one for 2021. As a treat, there are a few more tips than usual. Enjoy!

Happy holidays and see you on January 13th! ❄️


Changes to app launch sequence

On iOS 15, iOS might pre-warm your app by initialising the app delegate ]]></description>
        <link>https://ioscodereview.com/issues/13/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a4</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 09 Dec 2021 04:01:55 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Welcome to the 13th issue, the last one for 2021. As a treat, there are a few more tips than usual. Enjoy!</p><p>Happy holidays and see you on January 13th! ❄️</p><hr><h2 id="changes-to-app-launch-sequence">Changes to app launch sequence</h2><p>On iOS 15, iOS might pre-warm your app by initialising the app delegate &amp; co few minutes before the user launches the app. <code>application(:didFinishLaunching:...)</code> will be called when the app is finally launched, but other resources are loaded earlier.</p><p>The culprit is that some resources such as keychain might not be available, as the device might be still locked. So we shouldn't be initiating any work or for example checking of the API token presence earlier than <code>application(:didFinishLaunching:...)</code>. Check official documentation on this behaviour here: <a href="https://developer.apple.com/documentation/uikit/app_and_environment/responding_to_the_launch_of_your_app/about_the_app_launch_sequence?ref=ioscodereview.com">About the App Launch Sequence</a>.</p><h3 id="solving-mysterious-logout-issues-on-ios-15-source-diving"><a href="https://sourcediving.com/solving-mysterious-logout-issues-on-ios-15-8b818c089466?gi=bedb7055d213&ref=ioscodereview.com">Solving Mysterious Logout Issues on iOS 15 | Source Diving</a></h3><p>At Cookpad, after the public launch of iOS 15 we started to receive reports from users telling us that they were being repeatedly logged out when opening our app. This came as quite a surprise since…</p><h2 id="learning-from-cllocation-apis">Learning from CLLocation APIs</h2><p>Two learnings here: 1) desired location accuracy in <code>CoreLocation</code> can be set to a custom value in meters 2) how <em>not</em> to design an API 🤡 Here it's understandable though - this API comes from pre-Swift times and needs to be compatible with Objective-C, so it couldn't be modelled with enums with associated values. Thanks @Kilo_Loco for the find!</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/Kilo_Loco/status/1468354190850224128?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="printing-http-status-codes">Printing HTTP status codes</h2><p>Turns out Foundation has a method for producing human-readable strings from HTTP status codes: <code><a href="https://developer.apple.com/documentation/foundation/httpurlresponse/1409741-localizedstring?ref=ioscodereview.com">HTTPURLResponse.localizedString(forStatusCode:)</a></code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/toomasvahter/status/1454946289620291590?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="easy-boxes-in-switui">Easy boxes in SwitUI</h2><p><code><a href="https://developer.apple.com/documentation/swiftui/groupbox?ref=ioscodereview.com">GroupBox</a></code> is a SwiftUI component that replaces the setup with <code>VStack</code> + padding + mask. GroupBox can be customised with different styles, though there's only one provided out of the box. We can build our own styles,  here's a great article on that: <a href="https://swiftwithmajid.com/2020/10/15/mastering-groupbox-in-swiftui/?ref=ioscodereview.com">Mastering GroupBox in SwiftUI on Swift with Majid</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/gaudioaffectus/status/1464254742528409605?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="common-compositional-layouts-for-uicollectionview">Common compositional layouts for UICollectionView</h2><p>Filip has shared an awesome collection of various compositional layouts in his <a href="https://github.com/nemecek-filip/CompositionalDiffablePlayground.ios?ref=ioscodereview.com">Github repo</a>. If you are looking to start mastering <code>UICollectionViewCompositionalLayout</code> or <code>NSDiffableDataSource*</code>, I recommend checking it out.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nemecek_f/status/1425401952872058883?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="working-with-arrays-in-real-apps">Working with arrays in real apps</h2><p>If you need to take an item from an array, perform an asynchronous operation with it, and update it in the array, how do you do that safely without messing with indexes, which can change in the meantime? That requires some careful code that would need to be unit-tested.</p><p>This is a library for working with identifiable objects in collections, making it easy to access elements by identifiers instead of indexes. The readme goes more into the use-cases and problems with access by index.</p><h3 id="github-pointfreeco-swift-identified-collections"><a href="https://github.com/pointfreeco/swift-identified-collections?ref=ioscodereview.com">GitHub - pointfreeco/swift-identified-collections</a></h3><p>A library of data structures for working with collections of identifiable elements in an ergonomic, performant way.</p><h2 id="some-philosophy">Some philosophy</h2><p>Some of you are working in small companies, and some in bigger cos. This tweet isn't really code related, but I feel that it applies to anything. I've never thought of it this way before, but the distinction applies so clearly to all the teams I worked at. Which culture do you want to foster?</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/scottbelsky/status/1467469486521339905?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>☃️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #12 ]]></title>
        <description><![CDATA[ Hi there,

How is your week going?

I hope you enjoy today&#39;s tips. Let me know what you found most interesting by replying to this email 🙌


Tired of translatesAutoresizingMasksIntoConstraints?

Two neat ways to deal with the good old (and annoying)  translatesAutoresizingMasksIntoConstraints 👍






Or like that:

let label = UILabel().forAutoLayout( ]]></description>
        <link>https://ioscodereview.com/issues/12/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a5</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 25 Nov 2021 04:50:15 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>How is your week going?</p><p>I hope you enjoy today's tips. Let me know what you found most interesting by replying to this email 🙌</p><hr><h2 id="tired-of-translatesautoresizingmasksintoconstraints">Tired of translatesAutoresizingMasksIntoConstraints?</h2><p>Two neat ways to deal with the good old (and annoying)  <code><em>translatesAutoresizingMasksIntoConstraints</em></code> 👍</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ronyfadel/status/1462431756561403906?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Or like that:</p><p><code>let label = UILabel().forAutoLayout()</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ZiadeMarcus/status/1255509639015383044?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="type-safe-identifiers">Type-safe identifiers</h2><p>When we use string or int for identifiers, it can be easy to accidentally pass the wrong value to the function that takes a said identifier. <a href="https://swiftwithmajid.com/2021/02/18/phantom-types-in-swift/?ref=ioscodereview.com">@mecid wrote an article</a> on using phantom types to make API that works with identifiers type-safe, so the compiler does the checking for us.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mecid/status/1462753818882584578?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="understanding-swiftui-navigation">Understanding SwiftUI navigation</h2><p>A nice short write-up on the current state of navigation in SwiftUI.</p><p>While the repo itself contains tools that you can use in your code, the readme goes over the issues that out-of-the-box navigation API has and potential directions for solving them.</p><p>It's a valuable resource for understanding how to deal with navigation better, even if you don't wish to use third-party code.</p><h3 id="github-pointfreeco-swiftui-navigation-tools-for-making-swiftui-navigation-simpler-more-ergonomic-and-more-precise-"><a href="https://github.com/pointfreeco/swiftui-navigation?ref=ioscodereview.com">GitHub - pointfreeco/swiftui-navigation: Tools for making SwiftUI navigation simpler, more ergonomic and more precise.</a></h3><p>Tools for making SwiftUI navigation simpler, more ergonomic and more precise. - GitHub</p><h2 id="improving-old-code">Improving old code</h2><p>This is a great approach to working on old code. Old code can be improved significantly even by small refactoring - it's not always necessary to make big changes to make impact on code quality.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mdiep/status/1461378490352254978?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-non-fatal-errors">On non-fatal errors</h2><p>We often write checks like this one:</p><p><code>guard let requiredValue = value else { return }</code></p><p>In reality, when this case happens, the user will just see that nothing happens in response to their actions, and the developer will never know about such cases. Force unwrapping and crashing the app is not the answer either.</p><p>Antoine discusses ways to approach this problem in <a href="https://www.avanderlee.com/optimization/non-fatal-errors-vs-fatal-crashes/?ref=ioscodereview.com">his recent article</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1463135000535126021?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #11 ]]></title>
        <description><![CDATA[ Hi there,

I hope you enjoy this week’s findings ☀️🙌


On text truncation in SwiftUI

Once I spent a whole day debugging a text truncation issue in SwiftUI. I had a list of views with multiline text in each. All was good, but on rare occasions one of the views ]]></description>
        <link>https://ioscodereview.com/issues/11/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a6</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 11 Nov 2021 05:07:22 -0800</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>I hope you enjoy this week’s findings ☀️🙌</p><hr><h2 id="on-text-truncation-in-swiftui">On text truncation in SwiftUI</h2><p>Once I spent a whole day debugging a text truncation issue in SwiftUI. I had a list of views with multiline text in each. All was good, but on rare occasions one of the views would have truncated text. It would be seemingly random - the same item would be truncated or not depending on which position in the list it was in.</p><p>Eventually it turned out that I "just" needed to add <code><a href="http://Fixes this view at its ideal size in the specified dimensions.">fixedSize(...)</a></code> modifier to the <code>Text</code>s. It tells the text to take its ideal size (it's called intrinsic size in UIKit).</p><p>It bugs me that multiline text mostly works without it, so you think all is fine until you catch the truncation on some specific input. Do we <em>have to</em> use it on all multiline texts to avoid these issues? Apparently.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ZevEisenberg/status/1455555606245478408?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="compiler-enums-">Compiler + enums = 🧡</h2><p>This tip might be obvious to most devs, but this feature of enums is so useful to me, that it's worth sharing still. The idea is to always spell out all enum cases in <code>switch</code> statements, so the compiler helps out when a new case is added.</p><p>If you use <code>default</code> mainly because there are many cases that don't need handling, you can list cases with a comma: <code>case .a, .b, .c, .d, .e: break</code></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/toomasvahter/status/1424505703197143042?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="more-on-logging">More on logging</h2><p>Last issue included a tip on <code>print()</code> vs <code>os_log()</code>, and today I have a tip for you if you're still using <code><a href="https://developer.apple.com/documentation/foundation/1409759-nslog?ref=ioscodereview.com">NSLog()</a></code>. The first parameter is a format string, containing 0 or more <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html?ref=ioscodereview.com">format specifiers</a> starting with <code>%</code> (fx <code>%@</code> or <code>%f</code>). We shouldn't include interpolation in format strings - it's a matter of time until a printed url or error contains these symbols by accident - causing a crash.</p><figure class="kg-card kg-image-card"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/012/312/248/original/nslogbadaccess.png" class="kg-image" alt loading="lazy"></figure><h3 id="michael-tsai-blog-dangerous-nslog-calls-in-swift"><a href="https://mjtsai.com/blog/2021/11/02/dangerous-nslog-calls-in-swift/?ref=ioscodereview.com">Michael Tsai - Blog - Dangerous NSLog() Calls in Swift</a></h3><p>In the scenario of my crash, the interpolation of “url” and “error” results in surprise template placeholders, because of the presence of spaces in the path that the URL represents. In my tests, a file called “Open Program Ideas File” exists and is used to test some file manipulations. When the path to this file is encoded as a URL, the name of the file becomes “Open%20Program%20Ideas%20File”.  Each instance of “%20” followed by a letter is liable to be interpreted by NSLog as a printf-style format specifier. So as far as our filename’s string is concerned, we have “%20P”, “%20I”, and “%20F” threatening to cause trouble.</p><h2 id="passing-around-object-ids">Passing around object ids</h2><p>Quick tip from this morning on improving readability of your code that works with <code><a href="https://developer.apple.com/documentation/swift/identifiable?ref=ioscodereview.com">Identifiable</a></code> models. This protocol is part of Swift Standard Library, so it's relevant even if these models are not used in SwiftUI.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/DonnyWals/status/1458751452495687680?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/DonnyWals/status/1458753865365528578?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="bugs-not-an-if-but-when">Bugs: not an if, but when</h2><p>A bit of philosophical content here. It resonated with me a lot - I've been training table tennis most of my life, and I can relate to the analogy in this article. Unless you're significantly better than the opponent, you're actually just trying to minimize mistakes and keep the ball in play as long as possible.</p><p>When we develop long-living software, we're just trying not to lose - to bugs, technical debt, scaling issues. I love this way of looking at why we do unit tests, code reviews and regular maintenance.</p><blockquote><strong>ifwhen</strong></blockquote><h3 id="software-development-is-a-loser-s-game-by-ben-the-hosk-hosking-medium"><a href="https://thehosk.medium.com/software-development-is-a-losers-game-fc68bb30d7eb?ref=ioscodereview.com">Software development is a loser’s game | by Ben "The Hosk" Hosking | Medium</a></h3><p>I’m not saying developers are losers but most software developers are not beating software development, software development is beating them.</p><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below.</p><p>Thanks for your ongoing feedback! Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #10 ]]></title>
        <description><![CDATA[ Hi there,

Hope your Thursday is going the way you want it to go 🍁 Let&#39;s dive in 👇


async/await is really here

While it&#39;s undoubtedly a superior way to write asynchronous code, I generally stayed away from async/await-related tips, because no one could really use ]]></description>
        <link>https://ioscodereview.com/issues/10/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a7</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 28 Oct 2021 04:19:01 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🍁 Let's dive in 👇</p><hr><h2 id="async-await-is-really-here">async/await is really here</h2><p>While it's undoubtedly a superior way to write asynchronous code, I generally stayed away from async/await-related tips, because no one could really use them yet. I wrote about the issues <a href="https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-8-767711?ref=ioscodereview.com">few weeks ago</a>. But not for much longer!</p><p>Xcode 13.2 beta was released yesterday with support for backward deployment of async/await all the way back to iOS 13. This is achieved by embedding the Swift runtime with the app, like it was done before Swift gained ABI stability.</p><p>If you're open to trying it out for real in your projects, the Swift team is actively seeking feedback and issue reports during this beta period to help make the backport more stable. Just download Xcode 13.2 beta and try async/await features on your iOS 13 or iOS 14 device.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/johnsundell/status/1453429350272053251?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/dgregor79/status/1453432581622362112?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/johnsundell/status/1453673235384573958?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="print-vs-os_log-">print() vs os_log()</h2><p>A reminder about <code>print()</code> being slow. If you print something frequently, the lag can be really noticeable.</p><p>There's a way out - you can use <code>os_log</code> API instead. It doesn't slow the app down, and as an added benefit logs can be seen both in the debugger console and in Console.app, even on release builds from App Store. An even cooler thing is that interpolated values are redacted in release builds, unless included with <code>%{public}@</code> instead of <code>%@</code>.</p><p>To learn more about <code>os_log</code>, check out <a href="https://www.avanderlee.com/workflow/oslog-unified-logging/?ref=ioscodereview.com">the best article ever about os_log</a> from <a href="https://twitter.com/twannl?ref=ioscodereview.com">@twannl</a>. To learn about shortcomings of <code>os_log</code>, check out <a href="https://mjtsai.com/blog/2019/03/06/problems-with-os_log/?ref=ioscodereview.com">Problems with os_log</a> by <a href="https://twitter.com/mjtsai?ref=ioscodereview.com">@mjtsai</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/MartinLasek/status/1446574109228367880?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="managing-fallbacks">Managing fallbacks</h2><p>There are a lot of new views and modifiers in SwiftUI that can only be used from iOS 15 and up. If you support iOS 14 too, then you might use fallbacks there.</p><p><strong>@davedelong</strong> came up with a nice approach - housing custom fallback code under <code>.backport</code>, so it's easy to find usages in the project and remove fallbacks later when you drop support for iOS 14.</p><p>If it looks confusing, this short article by <a href="https://twitter.com/ralfebert?ref=ioscodereview.com">@ralfebert</a> goes step-by-step into arriving at this approach: <a href="https://www.ralfebert.de/swiftui/backporting-ios-view-modifiers/?ref=ioscodereview.com">Using iOS-15-only View modifiers in older iOS versions</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/davedelong/status/1446151822800945155?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="a-good-custom-operator">A good custom operator</h2><p>Custom operators are usually confusing to readers of the code, and many developers don't like them for this reason. But I found a really nice use-case shared by <strong>@twannl</strong>. The meaning is clear enough at call site (in my opinion), and it actually would save lots of typing in a project where colors are used extensively in the code:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/twannl/status/1453640612939501569?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>--</p><p>and just to end on a reassuring note - I think a lot of us feel this way right now. It's totally normal 🥲</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mkflint/status/1453433556559073281?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter further.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #9 ]]></title>
        <description><![CDATA[ Hi there,

It&#39;s that Thursday again 🥳 I found so many gems in the last few weeks, that today&#39;s issue contains more tips than usual. I also re-tweet additional tips throughout the week that didn&#39;t make it into the newsletter, so make sure to follow ]]></description>
        <link>https://ioscodereview.com/issues/9/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a8</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 14 Oct 2021 06:09:40 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>It's that Thursday again 🥳 I found so many gems in the last few weeks, that today's issue contains more tips than usual. I also re-tweet additional tips throughout the week that didn't make it into the newsletter, so make sure to follow <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> for even more tips.</p><hr><h2 id="-swiftui-previews">❤️ SwiftUI previews</h2><p>SwiftUI previews can be very handy for other use-cases besides previewing SwiftUI views.</p><p>You can use previews to preview UIKit views, which can save you dozens of hours in rebuilding to see your changes:</p><h3 id="github-theoriginalbit-previewview-make-use-of-swiftui-previews-for-uikit-"><a href="https://github.com/theoriginalbit/PreviewView?ref=ioscodereview.com">GitHub - theoriginalbit/PreviewView: Make use of SwiftUI Previews for UIKit!</a></h3><p>Make use of SwiftUI Previews for UIKit! Contribute to theoriginalbit/PreviewView development by creating an account on GitHub.</p><p>SwiftUI previews can also be used to preview app themes and other code-only visuals such as generated images:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1445732331990315018?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-manipulating-strings">On manipulating strings</h2><p>Swift's strings are unicode-compatible in the best way, counting the real displayed graphemes as the user would see them.</p><p>We need to be careful though when working with <code>NSString</code> APIs, because they deal with unicode differently. In the example below, <code>print((word as NSString).length)</code> would print <code>5</code> , not <code>4</code>. So be careful not to apply ranges returned from <code>NSString</code>-based APIs to  <code>String</code> instances.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/swiftandtips/status/1443576380474626060?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="-sf-symbols">❤️ SF Symbols</h2><p>SFSymbols are really powerful these days. They support thickness, styling and even multiple colors. What you see here on the screenshot is achievable with just native APIs on iOS 15. For an overview on how to use SFSymbols in SwiftUI and UIKit, check out <a href="https://www.hackingwithswift.com/articles/237/complete-guide-to-sf-symbols?ref=ioscodereview.com">The Complete Guide to SF Symbols by Paul Hudson</a>. There's also an <a href="https://developer.apple.com/sf-symbols/?ref=ioscodereview.com">official Mac app</a> for browsing and previewing all available symbols.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/JordanMorgan10/status/1445494218965749762?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="unit-testing-retain-cycles">Unit testing retain cycles</h2><p>Sometimes it's useful to test not only what a type does functionally, but also that there are no retain cycles and an instance deallocates as expected. This can be useful for view controllers and other complex classes dealing with closures and dependencies, where retain cycles are common.</p><p>Here's a short snippet by <strong>@ZiadeMarcus</strong> for verifying that an instance has deallocated after a test. It uses <code><a href="https://developer.apple.com/documentation/xctest/xctestcase/2887226-addteardownblock?ref=ioscodereview.com">addTeardownBlock</a></code> which is pretty neat on its own and can be used for other purposes too.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ZiadeMarcus/status/1448300525842227205?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="assert-failure-messages">Assert failure messages</h2><p>We write unit tests with the intention that they pass, but they really help us when they fail and catch errors in our code. So we should strive to have useful failure messages that hint at what's wrong. Not all assert failures provide insight out of the box - <a href="https://twitter.com/basthomas?ref=ioscodereview.com">@basthomas</a> gives an overview of commonly used XCTAssert* functions and how their failure messages are reported:</p><h3 id="-improving-your-xctassert-failure-messages-bas-blog"><a href="https://www.basbroek.nl/xctassert-asterisk?ref=ioscodereview.com">(Improving Your) XCTAssert* Failure Messages | Bas’ Blog</a></h3><p><br></p><h2 id="a-couple-of-debugging-tricks">A couple of debugging tricks</h2><p>In iOS 15 you can do <code>po [tableView _rowData]</code> in the debugger to print the internal geometry (e.g. heights, y-offsets for each row, etc) of the table view. This can be useful to track down why things look the way they do. For Swift, it would be <code>po tableView.value(forKey: "_rowData”)!</code>. This tip was shared by <a href="https://twitter.com/smileyborg?ref=ioscodereview.com">@smileyborg</a>.</p><p>Another trick is to print app's view controller hierarchy with <code>po [UIViewController _printHierarchy]</code>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/guillaumealgis/status/1225071479676723200?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #8 ]]></title>
        <description><![CDATA[ Hi there,

It&#39;s Thursday again ✨ Got a few really interesting things to share. Let&#39;s dive straight in 👇


Status of async/await

Considering to start using async/await for real? Here are some things worth knowing before you do. Backporting to older iOS versions is proving challenging ]]></description>
        <link>https://ioscodereview.com/issues/8/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5a9</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 30 Sep 2021 04:10:38 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>It's Thursday again ✨ Got a few really interesting things to share. Let's dive straight in 👇</p><hr><h2 id="status-of-async-await">Status of async/await</h2><p>Considering to start using async/await for real? Here are some things worth knowing before you do. Backporting to older iOS versions is proving challenging and might not happen; and a few serious issues and crashes have been found on the current version shipped with Xcode 13 / iOS 15.0.</p><p>I was excited to start using this for real, but will be holding off until there's a more stable version out there.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/XcodeReleases/status/1437937028193144834?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h3 id="swift-5-5-has-serious-stack-corruption-bugs-compiler-swift-forums"><a href="https://forums.swift.org/t/swift-5-5-has-serious-stack-corruption-bugs/52344?ref=ioscodereview.com">Swift 5.5 has serious stack corruption bugs! - Compiler - Swift Forums</a></h3><p>hi all, I’ve discovered several stack corruption bugs related to async/await which can be reproduced in simple test programs compiled with recent nightly toolchains. i have confirmed that two three four of these bugs are…</p><h2 id="catching-errors">Catching errors</h2><p>There are so many ways to write catch statements in Swift. It's as flexible as switch statements, and same as switch statements also verifies that all possible errors are handled, producing a compiler error otherwise.</p><p>Check out <a href="https://sarunw.com/posts/different-ways-to-catch-throwing-errors-in-swift/?ref=ioscodereview.com#catch-all-errors">Sarun's article</a> for detailed examples of each case. Here's <a href="https://docs.swift.org/swift-book/ReferenceManual/Patterns.html?ref=ioscodereview.com#grammar_pattern">the official language reference on patterns in Swift</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/sarunw/status/1438558971900661776?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="modern-dependency-injection">Modern dependency injection</h2><p>Dependency injection as a design pattern can manifest in different ways - from passing dependencies at initialisation to service locators and 3rd party libraries. (here's a nice <a href="https://quickbirdstudios.com/blog/swift-dependency-injection-service-locators/?ref=ioscodereview.com">overview</a> of the good old ways from 2019 by <a href="https://twitter.com/kofse?ref=ioscodereview.com">@kofse</a>)</p><p>Inspired by SwiftUI's <code>@Enviroment</code>, nowadays dependency injection can be made simpler and easier to use, thanks to Swift's latest features such as static subscripts, extensions, and property wrappers:</p><h3 id="dependency-injection-in-swift-using-latest-swift-features-swiftlee"><a href="https://www.avanderlee.com/swift/dependency-injection/?ref=ioscodereview.com">Dependency Injection in Swift using latest Swift features - SwiftLee</a></h3><p>Dependency Injection using latest Swift features allows you to mock data, and write tests easily without 3rd party dependencies.</p><h2 id="margins-on-uistackview">Margins on UIStackView</h2><p>Did you know that <code>UIStackView</code> supports layout margins out of the box? With one small boolean property <code><a href="https://developer.apple.com/documentation/uikit/uistackview/1616220-islayoutmarginsrelativearrangeme?ref=ioscodereview.com">isLayoutMarginsRelativeArrangement</a></code> we can ask the stack view to lay the content within its <code>layoutMargins</code> instead of its edges. And it respects safe area out of the box, thanks to UIView's <code><a href="https://developer.apple.com/documentation/uikit/uiview/2891101-insetslayoutmarginsfromsafearea?ref=ioscodereview.com">insetsLayoutMarginsFromSafeArea</a></code> which is true by default.</p><p>If you want to learn more about the layout margin system in UIKit, I gave a whole <a href="https://vimeo.com/362202970?ref=ioscodereview.com">talk</a> about it at NSSpain in 2019 :)</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/sarunw/status/1441450256194023425?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #7 ]]></title>
        <description><![CDATA[ Hi there,

Happy Xcode RC week! The release notes are extensive, but nonetheless are worth checking at some point, because there are many small improvements that are not mentioned anywhere else. I&#39;ll be going through the changelog myself, and will post anything that can improve our code 🙌

Let& ]]></description>
        <link>https://ioscodereview.com/issues/7/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5aa</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 16 Sep 2021 03:10:03 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Happy Xcode RC week! The <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes?ref=ioscodereview.com">release notes</a> are extensive, but nonetheless are worth checking at some point, because there are many small improvements that are not mentioned anywhere else. I'll be going through the changelog myself, and will post anything that can improve our code 🙌</p><p>Let's dive in 👇</p><hr><h2 id="crash-in-combine">Crash in Combine</h2><p>It's almost a tradition now to start the newsletter with a tip about an obscure Combine issue... This time, it turned out that <code><a href="https://developer.apple.com/documentation/combine/fail/breakpointonerror()?ref=ioscodereview.com">breakpointOnError()</a></code> crashes apps. To solve this, you can make an extension that conditionally uses this only if debugger is attached. But I just comment it out completely when not debugging 😅</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1437767688672133128?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="swiftui-combine-">SwiftUI + Combine = 🧡</h2><p>SwiftUI's <code><a href="https://developer.apple.com/documentation/swiftui/view/onreceive(_:perform:)?ref=ioscodereview.com">onReceive</a></code> opens some really interesting possibilities. Here's <strong>@danielsaidi</strong> with an example showcasing the power of SwiftUI when you sprinkle extra Combine on top. This code subscribes to a data binding of a UI element (a form in this case) and pipes changes into a save function. Makes the UI code really concise and pretty hard to break.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/danielsaidi/status/1433201914171334657?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="swift-api-design-guidelines">Swift API design guidelines</h2><p>Saw a tweet the other day, a person saying that they wish Swift had an official API guideline. So a refresher just in case - it does! Makes you a pro at writing function signatures that feel right at home in Swift.</p><h3 id="swift-org-api-design-guidelines"><a href="https://swift.org/documentation/api-design-guidelines/?ref=ioscodereview.com">Swift.org - API Design Guidelines</a></h3><p>Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns.</p><h2 id="lazy-local-variables">Lazy local variables</h2><p>Starting with Swift 5.5 (shipped with Xcode 13), we can use the <code>lazy</code> keyword on local variables. Code that had to use closures to achieve this lazy behaviour can now be simplified 🎉</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/011/125/140/original/screenshot_2021-09-15_at_23.05.14.png" class="kg-image" alt loading="lazy"><figcaption>Code example from the release notes</figcaption></figure><h2 id="time-based-git-diffs">Time-based git diffs</h2><p>Git supports a bunch of ways to reference commits (<em>revisions</em>): by commit hash (full or short), branch name, HEAD~n to jump back n commits, etc. Apparently you can not only reference commits, but also reference a specific moment in time. Thanks to <strong>@trevorbrindlejs</strong> for sharing this.</p><p>If you want to learn about all the ways to reference revisions, check <a href="https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection?ref=ioscodereview.com">the documentation</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/trevorbrindlejs/status/1428013045490626569?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #6 ]]></title>
        <description><![CDATA[ Hi there,

How is your Thursday going?

iOS 15 GM is right around the corner, people are buzzing about last moment API changes and additions. And I&#39;m here with some good old code improvement tips 😀👇


Waiting on multiple async calls

Have you seen code that&#39;s running ]]></description>
        <link>https://ioscodereview.com/issues/6/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5ab</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 02 Sep 2021 04:47:05 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>How is your Thursday going?</p><p>iOS 15 GM is right around the corner, people are buzzing about last moment API changes and additions. And I'm here with some good old code improvement tips 😀👇</p><hr><h2 id="waiting-on-multiple-async-calls">Waiting on multiple async calls</h2><p>Have you seen code that's running multiple async calls in a loop, calling completion on the last item in the loop? Or counting the number of callbacks called? I've seen it a lot, and the last time has prompted me to share this tip 🙂</p><p><a href="https://developer.apple.com/documentation/dispatch/dispatchgroup?ref=ioscodereview.com">DispatchGroup</a> allows you to wait on multiple async operations, as complex as they may be. The concept is simple: the dispatch group keeps track of how many tasks are outstanding (unfinished). <code>enter()</code> and <code>leave()</code> calls increment and decrement the internal counter. Once the counter reaches zero, your custom closure is called. Here's a small example by <strong>@joemasilotti</strong>:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/joemasilotti/status/1373036156871315456?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="conditional-modifiers-are-bad-">Conditional modifiers are bad? 😬</h2><p>Are you using conditional modifiers in SwiftUI? I am 🙈 Folks at <strong>@objcio</strong> came out with a detailed explanations on why it's not such a good idea. SwiftUI uses the type system for diffing of state, and conditional modifiers such as <code>applyIf(...)</code><em> </em>break that<em>.</em></p><p>The article also dives into why SwiftUI works the way it does, so check it out if you want to learn more: <a href="https://www.objc.io/blog/2021/08/24/conditional-view-modifiers/?ref=ioscodereview.com">Why Conditional View Modifiers are a Bad Idea</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/objcio/status/1430126941034659841?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="timers-scrolling-run-loops">Timers, scrolling, run loops</h2><p>When you use <code><a href="https://developer.apple.com/documentation/foundation/timer/2091889-scheduledtimer?ref=ioscodereview.com">Timer.sheduledTimerscheduledTimer(withTimeInterval:...)</a></code>, it will not trigger while the user is interacting with a scroll view, or is performing any other touch-tracking interaction. The timer will continue after the interaction has ended. That's because this convenience method auto-schedules the timer in the <code>.default</code> runloop mode, and the default mode doesn't check the timer during touch interactions.</p><p>If you want the timer to continue as normal during touch events, you'd have to init and schedule the timer with <code>.common</code> mode manually: <code>RunLoop.current.add(timer, forMode: .common)</code></p><p><strong>@qdoug</strong> shared a handy cheat-sheet for remembering which mode to use, as their names are super confusing:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/qdoug/status/1429833467425083392?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="review-the-resources-too">Review the resources too</h2><p>A fascinating anecdote shared by <strong>@krzyzanowskim</strong>. 98% of an app's size is icons, 11 MB each. That's nearly 1600x1600px. Why a png icon need to be this big? I bet this is not intentional, and these folks can reduce their app size at least 5x by including appropriately-sized images.</p><p>AKA this is a reminder to review the assets that are being introduced to the app, and not only code 🙃</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/krzyzanowskim/status/1428331763177295878?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="quick-2-in-1-tip">Quick 2-in-1 tip</h2><p>1) <a href="https://developer.apple.com/documentation/foundation/nscache?ref=ioscodereview.com">NSCache</a> exists and is a good alternative to a plain dictionary when you want to cache non-trivially sized items</p><p>2) How feedback is delivered is extremely important. Simply being friendly goes a long way ✨</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/trevorbrindlejs/status/1428013045490626569?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/swiftandtips/status/1432005825137156102?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘</p><p>Alright, that’s it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I’d love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #5 ]]></title>
        <description><![CDATA[ Hi there,

Hope your Thursday is going the way you want it to go 🌟

Let&#39;s dive in right away!


Check your back buttons

Do you remember about this obscure feature added in iOS 14? Holding the back button shows the navigation stack history and lets you navigate to ]]></description>
        <link>https://ioscodereview.com/issues/5/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5ac</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 19 Aug 2021 05:22:37 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🌟</p><p>Let's dive in right away!</p><hr><h2 id="check-your-back-buttons">Check your back buttons</h2><p>Do you remember about this obscure feature added in iOS 14? Holding the back button shows the navigation stack history and lets you navigate to any item. Cool feature, right? Not so fast...</p><p>The titles are taken from the back button. If you're still hiding the back button titles by setting <code>navigationItem.backButtonTitle = ""</code> , you will have this bug, where rows are just empty. I checked some popular apps and many of them have this issue 😵</p><p>Since iOS 14, there's a proper way to hide the back button title by using <code>backButtonDisplayMode</code>. <strong>@sarunw</strong> wrote a detailed guide on it, make sure to check it out!</p><p>PS. if you're on SwiftUI, remember to add the <code><a href="https://developer.apple.com/documentation/swiftui/view/navigationtitle(_:)-5di1u?ref=ioscodereview.com">.navigationTitle(_:)</a> </code>modifier even when you hide the navigation bar on that view.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/fb/d5/fbd5e4ac-4312-48bb-8ad2-a2b269212561/content/images/revue/items/images/010/562/663/original/history-stack-bug.png" class="kg-image" alt loading="lazy"><figcaption>the nasty history stack bug. source: sarunw.com</figcaption></figure><h3 id="a-new-way-to-manage-the-back-button-title-in-ios-14-with-backbuttondisplaymode-sarunw"><a href="https://sarunw.com/posts/new-way-to-manage-back-button-title-in-ios14/?ref=ioscodereview.com">A new way to manage the back button title in iOS 14 with backButtonDisplayMode | Sarunw</a></h3><p>Apple adds a new way to control where the back button will pick up its title. Let's see how this make thing a lot easier going forward.</p><h2 id="on-force-unwrapping">On force unwrapping</h2><p>Yet another debate on force unwrapping happened last week. With usually no end in sight for this polarising topic, we might have found <strong>the</strong> answer.</p><p>I loved this perspective from <strong>@johnhaney</strong>: both sides of the debate have the same goal - to account for the nil cases. The only difference is that for some, it's to think of it right away, and for others, only to do that if&amp;when the crashes happen in production and become a problem.</p><p>Check the whole thread if you want to read other interesting opinions.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/johnhaney/status/1423832649697792001?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="testing-throwing-code">Testing throwing code</h2><p>Test code is also code. <strong>@nicklockwood</strong> shares three tips for modernizing the implementation of your unit tests with <code>XCTUnwrap</code> and marking test functions as throwing:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1427942851309187075?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1427942852710051840?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1427942854182191108?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="pro-rebase-tip">Pro rebase tip</h2><p>If you're using rebase and are switching branches in the process, this tip will save you a bunch of friction. This is an older tweet, but I regularly meet people who are unaware of this trick, so here it is :)</p><p>If you're unsure why one would want to use rebase, I recommend reading the <a href="https://www.thinktecture.com/en/tools/demystifying-git-rebase/?ref=ioscodereview.com">Demystifying Git Rebase</a> article series.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/hybridcattt/status/1114596481359581185?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>🤘</p><p>Alright, that's it for today.</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? Want to see more, or less of certain kinds of tips? I'd love to hear from you. Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #4 ]]></title>
        <description><![CDATA[ Hi there. Did you know that it&#39;s already August?

In today&#39;s issue, among other things, @v_pradeilles shares two video tips, memory leaks in Combine make a come-back, and we fix Copilot&#39;s code. Let&#39;s dive in 👇


When not to use [weak self] ]]></description>
        <link>https://ioscodereview.com/issues/4/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5ad</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 05 Aug 2021 07:19:35 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there. Did you know that it's already August?</p><p>In today's issue, among other things, <a href="https://twitter.com/v_pradeilles?ref=ioscodereview.com">@v_pradeilles</a> shares two video tips, memory leaks in Combine make a come-back, and we fix Copilot's code. Let's dive in 👇</p><hr><h2 id="when-not-to-use-weak-self-">When not to use [weak self]</h2><p><a href="https://twitter.com/swiftandtips?ref=ioscodereview.com">@swiftandtips</a> found a well-structured writeup on when to use and not to use <em>[weak self]</em> in closures. Here's a concise chart to help you decide.</p><p>If you also want to learn the why's, read the full article: <a href="https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef?ref=ioscodereview.com">You don’t (always) need [weak self]</a> by <a href="https://twitter.com/BesherMaleh?ref=ioscodereview.com">@BesherMaleh</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/swiftandtips/status/1418559144739721219?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="lazy-collections-for-speed">Lazy collections for speed</h2><p>Love the new tip series by <a href="https://twitter.com/v_pradeilles?ref=ioscodereview.com">@v_pradeilles</a>. In this short video he demonstrates speeding up his code 400.000 times just by adding <em>.lazy.</em> Yes, only five characters 🔥 <a href="https://www.youtube.com/watch?v=YeGVrZJj-Mg&ref=ioscodereview.com">Watch full video on Youtube (6 min)</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/v_pradeilles/status/1417811945034555398?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="there-s-no-secrets-in-userdefaults">There's no secrets in UserDefaults</h2><p>And another tip from <a href="https://twitter.com/v_pradeilles?ref=ioscodereview.com">@v_pradeilles</a>. You've likely heard that saving sensitive data to UserDefaults is a bad idea, but perhaps weren't sure why?</p><p>Vincent recorded a short tutorial demonstrating how the data saved in UserDefaults can be easily accessed. <a href="https://www.youtube.com/watch?v=UAgtOTOH2nQ&ref=ioscodereview.com">Watch on Youtube (4 min)</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/v_pradeilles/status/1417498539387760655?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="memory-leaks-in-combine">Memory leaks in Combine</h2><p>We've touched on this topic in the <a href="https://newsletter.ioscodereview.com/issues/code-review-curated-code-improvement-tips-issue-3-684687?ref=ioscodereview.com">Issue #3</a>. Well, there are always more places to find retain cycles in.</p><p>If you're binding a publisher's values to a property of a class, watch out for which operator you use. Using <a href="https://developer.apple.com/documentation/combine/just/assign(to:on:)?ref=ioscodereview.com">.assign(to: \.property, on: self)</a> will retain <em>self</em> and may cause a retain cycle. On the other hand using <a href="https://developer.apple.com/documentation/combine/just/assign(to:)?ref=ioscodereview.com">.assign(to: $property)</a> retains the property's publisher, not <em>self</em>.</p><p>This old forums thread has an example of leaking code. Know your enemy!</p><h3 id="does-assign-to-produce-memory-leaks-using-swift-swift-forums"><a href="https://forums.swift.org/t/does-assign-to-produce-memory-leaks/29546?ref=ioscodereview.com">Does 'assign(to:)' produce memory leaks? - Using Swift - Swift Forums</a></h3><p>Hello there! I'm playing around with Combine and I've found a possible memory leak when using 'assign(to:)' to store stream result in current object. Let me show a couple of examples using 'assign(to:)' and 'sink' to co…</p><h2 id="remember-copilot">Remember Copilot?</h2><p>In <a href="https://newsletter.ioscodereview.com/issues/code-review-curated-code-improvement-tips-issue-2-677988?ref=ioscodereview.com">Issue #2</a> I asked for your suggestions on what can be improved in Copilot's code, and you sent some great suggestions! There are many things that could be improved there. Did you notice that it doesn't even compile?</p><p>I made a <a href="https://github.com/hybridcattt/remix-copilot-swift-playground/blob/main/RemixCopilot.playground/Contents.swift?ref=ioscodereview.com">playground with four improvement iterations</a>. Check it out to see if you've spotted everything, or if there's anything we missed 👀</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/krzyzanowskim/status/1410320595221463044?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? I’d love to hear your thoughts! Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #3 ]]></title>
        <description><![CDATA[ Hi there!

I hope your Thursday is going well ☀️ Today&#39;s issue covers topics such as architecture, Combine, Swift, SwiftUI, UIKit, and development process. Let&#39;s dive in!


Architectures are for humans

Last week a particular topic resonated through the community: the mental toll the different architectures bring ]]></description>
        <link>https://ioscodereview.com/issues/3/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5ae</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 22 Jul 2021 04:33:43 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there!</p><p>I hope your Thursday is going well ☀️ Today's issue covers topics such as architecture, Combine, Swift, SwiftUI, UIKit, and development process. Let's dive in!</p><hr><h2 id="architectures-are-for-humans">Architectures are for humans</h2><p>Last week a particular topic resonated through the community: the mental toll the different architectures bring on developers. The issue is especially prominent for complex architectures such as VIPER, which is known for having many similarly-named small files per each screen.</p><p><a href="https://twitter.com/collindonnell/status/1415052296002539525?ref=ioscodereview.com">@collinodonnel</a> shared his experience, which triggered many others to come forward. Dozens of developers shared similar experiences last week.</p><blockquote>Any task required routing through six classes, and I found myself physically exhausted when I had to interact with it.</blockquote><p>I have struggled with VIPER myself in exactly the same way.</p><p>Let this serve as a reminder to all of us. Not that VIPER is a bad architecture pattern, but that architectures are not <em>only</em> about clean code or testability. They're also about people. It's us humans who have to be able to understand the codebase, reason about it, and work on it - productively.</p><h2 id="retain-cycles-with-combine">Retain cycles with Combine</h2><p>Combine's <a href="https://developer.apple.com/documentation/combine/publisher/map(_:)-99evh?ref=ioscodereview.com"><em>map</em></a> operator retains the transform closure during the publisher's lifetime. When we pass a function declared on <em>self</em>, <em>self</em> is retained as well. If the subscription is kept alive by the same object, then we have an unbreakable retain cycle that prevents <em>self</em> from ever deallocating.</p><p>Marking <em>self</em> as <em>unowned</em> would leave the possibility of the app crashing. <a href="https://twitter.com/eneko?ref=ioscodereview.com">@eneko</a> shares a safe way to resolve the retain cycle:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/eneko/status/1416143468070465537?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="configuring-swiftui-views-with-environment">Configuring SwiftUI views with Environment</h2><p><a href="https://twitter.com/mecid?ref=ioscodereview.com">Majid</a> shares a real-life example of how to leverage custom environment variables to configure custom SwiftUI views. Check out his <a href="https://swiftwithmajid.com/2019/08/21/the-power-of-environment-in-swiftui/?ref=ioscodereview.com">article</a> if you want to understand SwiftUI's <em>Environment</em> better.  The way we do things in SwiftUI is definitely different from how we used to do them in UIKit 🙈</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mecid/status/1417079242463010822?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="reverse-arrays-for-free">Reverse arrays for free</h2><p>An interesting fact shared by <a href="https://twitter.com/swiftandtips?ref=ioscodereview.com">@swiftandtips</a>: reversing an array with <em>reversed()</em> doesn't use any new memory, and has constant time complexity (read: is very, very fast).  <a href="https://developer.apple.com/documentation/swift/array/1690025-reversed?ref=ioscodereview.com">Read documentation with examples here</a>.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/swiftandtips/status/1417289735165333506?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="detecting-orientation-changes-in-uikit">Detecting orientation changes in UIKit</h2><p>Why do we want to know about changes in device orientation? Most often it is to know about screen size changes. In today's variety of devices, device orientation is not the only possible cause for the app's window to change size - think moving the app to split screen on iPad. Individual view controllers can also change size - f.ex. when <a href="https://useyourloaf.com/blog/change-the-width-of-master-view-in-split-view-controller/?ref=ioscodereview.com">changing width of columns in UISplitViewController</a>.</p><p>Because of all this, it's much safer to rely on <a href="https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransitiontosize?ref=ioscodereview.com">viewWillTransitionToSize</a> for concrete size changes in view controllers, and on <a href="https://developer.apple.com/documentation/uikit/uitraitenvironment/1623516-traitcollectiondidchange?ref=ioscodereview.com">traitCollectionDidChange</a> for general changes in environment, such as size class, dark mode, preferred text size and so on. Thanks <a href="https://twitter.com/mluisbrown?ref=ioscodereview.com">@mluisbrown</a> for bringing this up!</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/mluisbrown/status/1413590534992670722?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="getting-unstuck-in-the-morning">Getting unstuck in the morning</h2><p>This tip is not about tweaking the code, but about tweaking your own development process. Are you sometimes feeling stuck when picking up a new task in the morning? There are some smart ideas in <a href="https://twitter.com/nicklockwood?ref=ioscodereview.com">@nicklockwood</a>'s thread.</p><p>My favourite trick is to create the pull request in the morning, even if I finished the implementation and pushed the commits the day before. Besides the productivity boost, it gives a chance to look at the solution with fresh eyes and think of missed edge cases.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/nicklockwood/status/1415594572848242691?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️</p><p>Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.</p><p>Got feedback? I’d love to hear your thoughts! Reply to this email or reach out on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #2 ]]></title>
        <description><![CDATA[ Hi there!

Even though it&#39;s summer and many are on vacation, there is no shortage of things that we can learn from our awesome Apple developer community.

I hope you enjoy this week&#39;s findings ☀️🙌


Function annotations for structs

If you write Swift, most likely you use ]]></description>
        <link>https://ioscodereview.com/issues/2/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5af</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Thu, 08 Jul 2021 03:37:35 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there!</p><p>Even though it's summer and many are on vacation, there is no shortage of things that we can learn from our awesome Apple developer community.</p><p>I hope you enjoy this week's findings ☀️🙌</p><hr><h2 id="function-annotations-for-structs">Function annotations for structs</h2><p>If you write Swift, most likely you use structs <em>a lot</em>. <a href="https://twitter.com/johnsundell?ref=ioscodereview.com">John Sundell</a> goes in depth on how marking functions in structs <em>mutating</em> can help you make code more structured and concise.</p><h3 id="mutating-and-non-mutating-swift-contexts-swift-by-sundell"><a href="https://swiftbysundell.com/articles/mutating-and-nonmutating-swift-contexts/?ref=ioscodereview.com">Mutating and non-mutating Swift contexts | Swift by Sundell</a></h3><p>What sort of capabilities that a mutating Swift context has, and what the mutating and nonmutating keywords do.</p><h2 id="handling-actions-in-uibutton">Handling actions in UIButton</h2><p>Did you know about <a href="https://developer.apple.com/documentation/uikit/uicontrol/event/1618222-primaryactiontriggered?ref=ioscodereview.com">UIControl.Event.primaryActionTriggered</a>? It's been around since iOS 9.0, and it makes <em>touchUpInside </em>obsolete for button action handling. It also makes accidentally picking <em>touchUpOutside</em> and wondering why the button won't work for an hour less likely. <a href="https://developer.apple.com/documentation/uikit/uicontrol/event?ref=ioscodereview.com"><em>touch*</em> events</a> are still useful for handling touch movements in custom controls, but we can simply use <em>primaryAcitionTriggered</em> in day-to-day. via <a href="https://twitter.com/_mochs?ref=ioscodereview.com">@_mochs</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/_mochs/status/1412470444595109888?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="on-testing-and-refactoring">On testing and refactoring</h2><p>Stumbled onto this quote from 2017, and I just had to share it. In my view, this is the best way for us developers to view ourselves as professionals in our field.</p><p>"I don't ask permission to write a test or refactor, any more than I ask for permission to write an if statement or a for loop" - <a href="https://twitter.com/RonJeffries?ref=ioscodereview.com">@RonJeffries</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/chrisshinkle/status/923187864913039360?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="working-on-multiple-branches-in-git">Working on multiple branches in git</h2><p><a href="https://twitter.com/rockbruno_?ref=ioscodereview.com">@rockbruno_</a> uncovered an awesome git feature: <em>git worktree</em> allows us to check out multiple branches at once in the same repo. <em>git worktree</em> has benefits over cloning multiple copies: you save on disk space (in case your repo has long history) and all worktrees share the same local branches and stashes.</p><p>You can use worktrees to have parallel branches checked out long term, f.ex. an older version of the app for comparing functionality, or just to quickly check out coworker's branch during code review.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/rockbruno_/status/1412743209633992707?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="let-s-review-copilot-s-code-">Let's review Copilot's code!</h2><p>A lot has been said already about Github's Copilot tool, good and bad. I don't have access yet, and I'm sure not many of you do. While we wait, let's review Copilot-suggested code!</p><p>How many bugs and improvement opportunities can you find in this piece shared by <a href="https://twitter.com/krzyzanowskim?ref=ioscodereview.com">@krzyzanowskim</a>?</p><p><a href="https://forms.gle/gnmVJdpujgAQJkAJ9?ref=ioscodereview.com">Let me know by filling a one-question form</a>, all anonymous of course. If I get enough replies, I will share most popular ones on our <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">Twitter</a> next week.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/krzyzanowskim/status/1410320595221463044?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>✌️</p><p>What did you think about these tips? I’d love to hear your thoughts on Twitter via <a href="https://twitter.com/ios_code_review?utm_campaign=%20%EF%A3%BF%20Code%20Review%20%7C%20%20Curated%20code%20improvement%20tips&utm_medium=email&utm_source=Revue%20newsletter">@ios_code_review</a> or over email at <a href="mailto:ioscodereview@hybridcattt.com?utm_campaign=%20%EF%A3%BF%20Code%20Review%20%7C%20%20Curated%20code%20improvement%20tips&utm_medium=email&utm_source=Revue%20newsletter">ioscodereview@hybridcattt.com</a> 🙌</p> ]]></content:encoded>
    </item>
    <item>
        <title><![CDATA[ Issue #1 - Highlights from 2020 ]]></title>
        <description><![CDATA[ Hi there. How awesome of you to stop by!

This issue was actually never sent to anyone. I&#39;ve just created the newsletter, and this is a sample of how the future issues might look. I will share the valuable code improvement tips I stumble upon while browsing Twitter, ]]></description>
        <link>https://ioscodereview.com/issues/1/</link>
        <guid isPermaLink="false">6383ae5c4685dc003c51a5b0</guid>
        <category><![CDATA[  ]]></category>
        <dc:creator><![CDATA[ IOS Code Reviews ]]></dc:creator>
        <pubDate>Wed, 30 Jun 2021 05:23:30 -0700</pubDate>
        <media:content url="" medium="image"/>
        <content:encoded><![CDATA[ <p>Hi there. How awesome of you to stop by!</p><p>This issue was actually never sent to anyone. I've just created the newsletter, and this is a sample of how the future issues might look. I will share the valuable code improvement tips I stumble upon while browsing Twitter, spiced by occasional comments from my side. I cover Swift, Objective-C, UIKit, SwiftUI and much more. The plan is to send the newsletter every two weeks or once a month.</p><p>This issue contains my most favourite tips from 2020. Code improvement tips rarely age, so I hope you find these useful 🙌</p><hr><h2 id="change-suggestions-in-pr-comments">Change suggestions in PR comments</h2><p>While multiline change suggestions were introduced on Github all the way back in February 2020, it's such a time saver during code reviews, that it is worth reminding about.</p><p>When a you use <a href="https://docs.github.com/en/github/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request?ref=ioscodereview.com">change suggestions in PR comments</a>, the changes can be incorporated automatically with a click of a button in the web UI, without having to first apply requested changes locally and then pushing to remote.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/github/status/1232734207853522949?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="tired-of-translatesautoresizingmasksintoconstraints">Tired of translatesAutoresizingMasksIntoConstraints?</h2><p>This is the nicest way I’ve <strong>ever</strong> seen to deal with <em>translatesAutoresizingMasksIntoConstraints</em>.</p><p><em>let label = UILabel().forAutoLayout()</em> // just like that 🤯 by <a href="https://twitter.com/ZiadeMarcus?ref=ioscodereview.com">@ZiadeMarcus</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/ZiadeMarcus/status/1255509639015383044?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="access-control-for-performance">Access control for performance</h2><p>It's not obvious that choices such as marking types and members <em>private</em> or <em>final</em>, or choosing between using <em>struct</em> or <em>class</em> are not only code style preferences, but also affect performance. Read the article by <a href="https://avitsadok.medium.com/?ref=ioscodereview.com">Avi Tsadok</a>:</p><h3 id="9-ways-to-boost-your-swift-code-performance-by-avi-tsadok-better-programming"><a href="https://betterprogramming.pub/9-ways-to-boost-your-swift-code-performance-56e0986dd9ec?gi=b200951a424a&ref=ioscodereview.com">9 Ways to Boost Your Swift Code Performance | by Avi Tsadok | Better Programming</a></h3><p>Swift is a fast language and it gets faster in every release. iOS devices are also fast, so the chances are these tips won’t be needed at all. Even in those cases where we do bump into performance…</p><h2 id="any-documentation-no-documentation">Any documentation &gt; no documentation</h2><p>A reminder that even smallest bits of documentation can be helpful. via <a href="https://twitter.com/SergDort?ref=ioscodereview.com">@SergDort</a></p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/SergDort/status/1333421850819485697?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="minimalistic-functions">Minimalistic functions</h2><p>I love this idea of functions only taking the most specific parameters they need, courtesy of <a href="https://twitter.com/Jonathanff?ref=ioscodereview.com">@Jonathanff</a>. This approach doesn't only improve reusability, but also reduces unwanted side effects (possibility of changing something you didn't mean to change) and makes code easier to review. It's not a silver bullet though, so use with care.</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/Jonathanff/status/1290663787964465152?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="tech-debt-as-a-tool">Tech debt as a tool</h2><p>Adding tech debt is acceptable in some cases, and is often necessary. <a href="https://twitter.com/danielsaidi?ref=ioscodereview.com">@danielsaidi</a> shares a solid approach to accepting technical debt:</p><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/danielsaidi/status/1329041213362745350?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><h2 id="to-end-on-a-fun-note-">To end on a fun note...</h2><figure class="kg-card kg-embed-card">
<blockquote class="twitter-tweet"><a href="https://twitter.com/simonnickel/status/1309763015819104256?ref=ioscodereview.com"></a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Nothing and no one is perfect, let's just remember that we're all human 😇</p><p>✌️</p><p>What did you think about these tips? I'd love to hear your thoughts on Twitter via <a href="https://twitter.com/ios_code_review?ref=ioscodereview.com">@ios_code_review</a> or  over email at <a href="mailto:ioscodereview@hybridcattt.com">ioscodereview@hybridcattt.com</a> 🙌</p> ]]></content:encoded>
    </item>

    <item>
      <title>[bonus issue]  iOS Code Review - Issue #36 | Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Yesterday I've sent out the issue #35, and it was flagged as spam by Gmail. It was due to technical problems on Revue side, not sure what exactly. They got fixed after I reached out to support, and now the emails are delivered ok.</p><p>I know that a lot of you are looking forward to receiving the newsletter, but I didn't want to just redeliver the same email again. Hence this bonus issue with two great articles 😊 </p><p>If you're on gmail, check your spam folder for the previous email, and please mark it as "not spam" 🙏 If you're not on Gmail, I hope you don't mind the bonus issue 💚</p><p>I am investigating changing to a more reliable email platform, so the email layout might be slightly different next time. </p>]]></description>
      <pubDate>Fri, 04 Nov 2022 13:07:52 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/bonus-issue-ios-code-review-issue-36-curated-code-improvement-tips-1440142</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #35 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Welcome to the issue #35 👋 Enjoy!</p>]]></description>
      <pubDate>Thu, 03 Nov 2022 12:33:05 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-35-curated-code-improvement-tips-1417649</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #34 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Welcome to issue #34 👋 Hope you learn something new today! </p><p>I also got the first sponsor this time - I'm really excited to be able to get some funds to continue growing the newsletter! I'm already investing them into improving my curation workflow and building a custom landing page. If you're looking for a job, check out the sponsored section at the end ☺️</p>]]></description>
      <pubDate>Thu, 20 Oct 2022 11:05:16 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-34-curated-code-improvement-tips-1395950</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #33 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Welcome to the 33rd issue 👋 We're back to a classic five-tips structure, and I hope you find something interesting today. </p><p>As an innovation, I've included a new section at the bottom with featured jobs. They're not sponsored this time, but I hope to get sponsored job or indie app ads in the future. The code tips themselves will never have any promoted content in them, only what I truly think is best ☺️</p>]]></description>
      <pubDate>Thu, 06 Oct 2022 11:12:57 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-33-curated-code-improvement-tips-1373081</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #32 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there!</p><p>Hope you're doing good and working toward your goals, whatever they are (whether that's work, resting more, spending more time with family, or protecting what's yours). </p><p>Today I have a couple of longer sections - hope you enjoy the read, and I'm always curious to hear your thoughts!</p><p>Let's dive in 👇👇</p>]]></description>
      <pubDate>Thu, 22 Sep 2022 10:30:02 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-32-curated-code-improvement-tips-1348476</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #31 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there, </p><p>Did you enjoy the Apple event yesterday? Whether you're into the latest tech, or in the camp of anti-consumerism, hope you had a nice day 🙂 </p><p>On Twitter it might seem that <em>everyone</em> is so excited about the new phones/watches/etc. But that's just the bubble. I, for one, will not be buying a new iPhone or watch any time soon - will keep enjoying my 2-year-old XS and series 5. To whomever needs to hear this, it's totally ok not to jump on buying the newest thing, but also it's ok to do so. </p><p>Now let's dive in, hope you learn something new today </p>]]></description>
      <pubDate>Thu, 08 Sep 2022 10:50:25 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-31-curated-code-improvement-tips-1327246</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #30</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>I hope the summer is treating you well, and you're progressing toward your goal, whatever it is!</p><p>As promised in the last issue, here's me sharing behind-the-scenes on how I make the newsletter issues: <a href="https://youtu.be/CgTqqkzeeh8" target="_blank">https://youtu.be/CgTqqkzeeh8</a></p><p>Let's dive in 👇</p>]]></description>
      <pubDate>Thu, 25 Aug 2022 11:13:00 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-30-1306376</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #29 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>As I'm writing this, I am recording a show-and-tell video sharing a bit about my process creating this newsletter. I'll share it on Twitter and in the next issue, so stay tuned :) </p><p>I hope you find something interesting in my collection today 👇</p>]]></description>
      <pubDate>Thu, 11 Aug 2022 10:30:02 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-29-curated-code-improvement-tips-1285726</link>
    </item>
    <item>
      <title> iOS Code Review - Issue #28 |  Curated code improvement tips</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>I hope you find something useful or interesting in today's collection ✨ </p>]]></description>
      <pubDate>Thu, 28 Jul 2022 11:12:02 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-issue-28-curated-code-improvement-tips-1266658</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #27</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>It's getting harder and harder to not share cool things from iOS 16 (that we can't yet use). I'm managing to resist so far. Hope you find something interesting and useful in today's collection!</p><p>By the way, if you enjoy reading the newsletter - send it to a colleague ☺️</p>]]></description>
      <pubDate>Thu, 14 Jul 2022 11:10:44 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-27-1248058</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #26</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Every time I sit down to write an intro to an issue, I struggle between staying positive and the desire to address current events in the outside world. And every time I land on the decision to let this newsletter be a small island on the internet dedicated to learning something new in the field we're passionate about. </p><p>If you are affected by war, the pandemic, or any of the other struggles in our crazy world - know that I think of you every time I write this 💛 </p><p>And thanks to all of you for being loyal readers! Seeing the high open rates and receiving your feedback keeps my heart warm(-er) ☺️</p><p>So I hope you find something interesting in today's collection. Let's dive in?</p>]]></description>
      <pubDate>Thu, 30 Jun 2022 10:52:20 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-26-1225711</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #25</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Hope you had a wonderful WWDC week! I myself have been on vacation (and still am), and only checked out the keynote and saw some tweets from the community. </p><p>Other newsletters have featured lots of WWDC-related articles - for example I loved the latest <a href="https://iosdevweekly.com" target="_blank">iOS Dev Weekly</a> which was 100% about WWDC.</p><p>I tend to forget all the new things by the time I can use them for real, so I'll be featuring more of the new APIs after Xcode 14 ships in September. My goal has always been to share things that can be used right away in real projects (gotta be honest it's also convenient because I could continue spending the vacation offline 😋)</p><p>I was also interviewed on the <a href="https://www.buzzsprout.com/1414396/10721946" target="_blank">AppForce1 podcast</a>, where I shared a bit about how I make the newsletter ☺️  </p><p>Now let's dive in!</p>]]></description>
      <pubDate>Thu, 16 Jun 2022 10:30:01 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-25-1206264</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #24</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>As promised, today's issue is a special one, and I'm really excited to bring it to you. I wanted to spice things up a bit and invite a guest curator to create this issue. Because why not?</p><p>Say hi to <a href="https://twitter.com/basthomas" target="_blank">Bas Broek</a> - he will be curating the collection today. Bas had been authoring <a href="https://swiftweeklybrief.com/" target="_blank">Swift Weekly Brief (sadly discontinued)</a> for 2 years before joining the accessibility team at Apple. Now he's back to the community and shares his favourite bits of wisdom with us below 👇 😌</p><p>--------------------</p><p>This is Bas; I'm a friend of Marina's. As she reached out to me asking if I'd be up for writing an issue, I immediately said yes!</p><p>Having curated a newsletter before, I know it can be quite a bit of work; having the community help out was always a highlight of writing the newsletter, so I'm always happy to return that favor.</p><p>Enjoy!</p>]]></description>
      <pubDate>Thu, 02 Jun 2022 10:41:20 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-24-1186350</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #23</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>WWDC is coming soon, are you excited? I am, but also looking forward to some vacation time. Not sure yet how much of catching up with the freshest-and-greatest content I'll do in June, but either way there will be some interesting stuff to share.</p><p>Also stay tuned for the next issue #24 on June 1st, it will be a very special one 🤩</p><p>Now, let's dive in 👇</p>]]></description>
      <pubDate>Thu, 19 May 2022 11:03:01 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-23-1165731</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #22</title>
      <description type="html"><![CDATA[<p>Hi there, </p><p>Hope you enjoy today's collection 🙌</p>]]></description>
      <pubDate>Thu, 05 May 2022 10:51:40 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-22-1145218</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #21</title>
      <description type="html"><![CDATA[<p>Hi there, </p><p>Hope you're safe, wherever you are. I'm excited to share this week's findings with you! </p><p>This time I'm doing something new in addition to the usual tips. The pandemic has been hash on the conference scene, and the next conference season is coming up. I figured I'd highlight some conferences that are still looking for speakers. </p><p>Enjoy! ☀️</p>]]></description>
      <pubDate>Thu, 21 Apr 2022 11:21:14 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-21-1124111</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #20</title>
      <description type="html"><![CDATA[<p>Hi there, </p><p>Can't believe this is already the 20th issue  🎉 A milestone for sure. Thank you for your continuous support and feedback - and for spreading the word!</p>]]></description>
      <pubDate>Thu, 07 Apr 2022 10:47:31 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-20-1101122</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #19</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>The world is still a mess, but I'm really excited to bring you some learnings today. Enjoy! 🙌</p>]]></description>
      <pubDate>Thu, 24 Mar 2022 11:50:04 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-19-1078688</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #18</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>I hope you enjoy today's content. Let's dive in 👇</p>]]></description>
      <pubDate>Thu, 10 Mar 2022 11:47:29 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-18-1055645</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #17</title>
      <description type="html"><![CDATA[<p>I spent the whole morning thinking about whether it's appropriate to send out an issue today. For the sake of consistency I decided in favour of delivering on the promise of code improvement tips in your inbox every two weeks.</p><p>This time I got no cheerful words though. If you're able to enjoy something today - I hope you enjoy these tips.</p>]]></description>
      <pubDate>Thu, 24 Feb 2022 11:04:06 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-17-1032468</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #16</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>This time I have exciting news to share - last week we crossed the 1000 subscribers mark 🥳 It's so honouring to be able to share the learnings with such a wide community from all around the world. Thank you for tuning in!</p><p>And now, let's dive into the tips 👇</p>]]></description>
      <pubDate>Thu, 10 Feb 2022 11:16:37 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-16-1008909</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #15</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🌟 Let's dive into this week's highlights! </p>]]></description>
      <pubDate>Thu, 27 Jan 2022 11:57:44 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-15-985276</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #14</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Welcome to the first issue of 2022! ☀️</p><p>Hope everyone had lovely holidays. I did, and am pumped to jump back into sharing tips regularly. Enjoy!</p>]]></description>
      <pubDate>Thu, 13 Jan 2022 12:22:06 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-14-922655</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #13</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Welcome to the 13th issue, the last one for 2021. As a treat, there are a few more tips than usual. Enjoy!</p><p>Happy holidays and see you on January 13th! ❄️</p>]]></description>
      <pubDate>Thu, 09 Dec 2021 12:01:55 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-13-898954</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #12</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>How is your week going? </p><p>I hope you enjoy today's tips. Let me know what you found most interesting by replying to this email 🙌</p>]]></description>
      <pubDate>Thu, 25 Nov 2021 12:50:15 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-12-869205</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #11</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>I hope you enjoy this week’s findings ☀️🙌</p>]]></description>
      <pubDate>Thu, 11 Nov 2021 13:07:22 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-11-831765</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #10</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🍁 Let's dive in 👇</p>]]></description>
      <pubDate>Thu, 28 Oct 2021 11:19:01 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-10-810923</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #9</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>It's that Thursday again 🥳 I found so many gems in the last few weeks, that today's issue contains more tips than usual. I also re-tweet additional tips throughout the week that didn't make it into the newsletter, so make sure to follow <a href="https://twitter.com/ios_code_review" target="_blank">@ios_code_review</a> for even more tips. </p>]]></description>
      <pubDate>Thu, 14 Oct 2021 13:09:40 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-9-789293</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #8</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>It's Thursday again ✨ Got a few really interesting things to share. Let's dive straight in 👇</p>]]></description>
      <pubDate>Thu, 30 Sep 2021 11:10:38 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-8-767711</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #7</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Happy Xcode RC week! The <a href="https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes" target="_blank">release notes</a> are extensive, but nonetheless are worth checking at some point, because there are many small improvements that are not mentioned anywhere else. I'll be going through the changelog myself, and will post anything that can improve our code 🙌</p><p>Let's dive in 👇</p>]]></description>
      <pubDate>Thu, 16 Sep 2021 10:10:03 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-7-747728</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #6</title>
      <description type="html"><![CDATA[<p>Hi there, </p><p>How is your Thursday going? </p><p>iOS 15 GM is right around the corner, people are buzzing about last moment API changes and additions. And I'm here with some good old code improvement tips 😀👇</p>]]></description>
      <pubDate>Thu, 02 Sep 2021 11:47:05 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-6-728425</link>
    </item>
    <item>
      <title> iOS Code Review |  Curated code improvement tips - Issue #5</title>
      <description type="html"><![CDATA[<p>Hi there,</p><p>Hope your Thursday is going the way you want it to go 🌟</p><p>Let's dive in right away!</p>]]></description>
      <pubDate>Thu, 19 Aug 2021 12:22:37 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/ios-code-review-curated-code-improvement-tips-issue-5-713957</link>
    </item>
    <item>
      <title>  Code Review |  Curated code improvement tips - Issue #4</title>
      <description type="html"><![CDATA[<p>Hi there. Did you know that it's already August?</p><p>In today's issue, among other things, <a href="https://twitter.com/v_pradeilles" target="_blank">@v_pradeilles</a> shares two video tips, memory leaks in Combine make a come-back, and we fix Copilot's code. Let's dive in 👇</p>]]></description>
      <pubDate>Thu, 05 Aug 2021 14:19:35 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/code-review-curated-code-improvement-tips-issue-4-698282</link>
    </item>
    <item>
      <title>  Code Review |  Curated code improvement tips - Issue #3</title>
      <description type="html"><![CDATA[<p>Hi there!</p><p>I hope your Thursday is going well ☀️ Today's issue covers topics such as architecture, Combine, Swift, SwiftUI, UIKit, and development process. Let's dive in! </p>]]></description>
      <pubDate>Thu, 22 Jul 2021 11:33:43 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/code-review-curated-code-improvement-tips-issue-3-684687</link>
    </item>
    <item>
      <title>  Code Review |  Curated code improvement tips - Issue #2</title>
      <description type="html"><![CDATA[<p>Hi there! </p><p>Even though it's summer and many are on vacation, there is no shortage of things that we can learn from our awesome Apple developer community. </p><p>I hope you enjoy this week's findings ☀️🙌</p>]]></description>
      <pubDate>Thu, 08 Jul 2021 10:37:35 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/code-review-curated-code-improvement-tips-issue-2-677988</link>
    </item>
    <item>
      <title> Code Review - Issue #1 | Highlights from 2020</title>
      <description type="html"><![CDATA[<p>Hi there. How awesome of you to stop by!</p><p>This issue was actually never sent to anyone. I've just created the newsletter, and this is a sample of how the future issues might look. I will share the valuable code improvement tips I stumble upon while browsing Twitter, spiced by occasional comments from my side. I cover Swift, Objective-C, UIKit, SwiftUI and much more. The plan is to send the newsletter every two weeks or once a month.</p><p>This issue contains my most favourite tips from 2020. Code improvement tips rarely age, so I hope you find these useful 🙌</p>]]></description>
      <pubDate>Wed, 30 Jun 2021 12:23:30 +0000</pubDate>
      <link>https://newsletter.ioscodereview.com/issues/code-review-issue-1-highlights-from-2020-675182</link>
    </item>

</channel>
</rss>