<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Daniel develops in Swift]]></title><description><![CDATA[Daniel develops in Swift]]></description><link>https://articles.danielkasaj.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 18:15:50 GMT</lastBuildDate><atom:link href="https://articles.danielkasaj.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[SwiftUI ScrollView Centered Items with ScrollTargetBehavior]]></title><description><![CDATA[Let’s make a ScrollView show a bunch of views horizontally, and center each one as the user scrolls, while also showing edges of adjacent ones. In a hurry to get the entire code? It’s at the bottom of the article.

Any time a ScrollView scrolls, it c...]]></description><link>https://articles.danielkasaj.com/swiftui-scrollview-centered-items-with-scrolltargetbehavior</link><guid isPermaLink="true">https://articles.danielkasaj.com/swiftui-scrollview-centered-items-with-scrolltargetbehavior</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[UI]]></category><dc:creator><![CDATA[Daniel Kašaj]]></dc:creator><pubDate>Sat, 21 Dec 2024 11:19:09 GMT</pubDate><content:encoded><![CDATA[<p>Let’s make a ScrollView show a bunch of views horizontally, and center each one as the user scrolls, while also showing edges of adjacent ones. In a hurry to get the entire code? It’s at the bottom of the article.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734777987488/38d11667-8b08-429f-92be-1c691ca6593c.gif" alt class="image--center mx-auto" /></p>
<p>Any time a ScrollView scrolls, it calculates where it’s going to finish. You can “sneakily” steal those calculations, modify them, replace the originals, and see scrolling finish where you just told it to. Super secret subversion stuff. 🥷</p>
<p>This gets done by supplying the <code>ScrollView</code> with a <code>ScrollTargetBehavior</code>.<br />That’s going to be a struct adhering to the <code>ScrollTargetBehavior</code> protocol, implementing only one method:<br /><code>func updateTarget(_ target: inout ScrollTarget, context: TargetContext)</code></p>
<p>In that method, <code>ScrollTarget</code> is a struct representing where the scrolling will finish. <code>TargetContext</code> will give you various info on the <code>ScrollView</code> - where it was when the gesture began, which way it’s scrolling, with what velocity, what the total scrolling content size is, and what the container size (visible view) is.</p>
<p>Because <code>ScrollTarget</code> is an <code>inout</code> parameter, we can modify it and make the <code>ScrollView</code> land somewhere else than originally intended.</p>
<p>Here’s what I did to make it center on each view (follow code in gist below, lines 49-53):</p>
<ul>
<li><p>took the top left coordinate where the scrolling was supposed to land and figured out which view that would be</p>
</li>
<li><p>calculated the top left coordinate of that view</p>
</li>
<li><p>figured out how much remaining space there is when the view’s width is deducted from ScrollView’s width on screen</p>
</li>
<li><p>made scrollView land not on the top left coordinate of the view, but “half the remaining space” before it</p>
</li>
</ul>
<p>Here’s the code:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="77b7c68e0b5d01d814382c03a824a6d1"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/dkasaj/77b7c68e0b5d01d814382c03a824a6d1" class="embed-card">https://gist.github.com/dkasaj/77b7c68e0b5d01d814382c03a824a6d1</a></div>]]></content:encoded></item><item><title><![CDATA[Tips for localizing SwiftUI apps]]></title><description><![CDATA[I’ve recently localized my app Workout Shoes to German without ever touching the Localizable.strings file, and I’d like to share a few lessons learned:
Let Xcode extract all the phrases for you
Xcode has a menu command Product > Export Localizations…...]]></description><link>https://articles.danielkasaj.com/tips-for-localizing-swiftui-apps</link><guid isPermaLink="true">https://articles.danielkasaj.com/tips-for-localizing-swiftui-apps</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[localization]]></category><category><![CDATA[Xcode]]></category><category><![CDATA[Swift]]></category><dc:creator><![CDATA[Daniel Kašaj]]></dc:creator><pubDate>Sat, 26 Aug 2023 10:15:30 GMT</pubDate><content:encoded><![CDATA[<p>I’ve recently localized my app <a target="_blank" href="https://apps.apple.com/app/workout-shoes/id1641520824">Workout Shoes</a> to German <strong>without ever touching the Localizable.strings file</strong>, and I’d like to share a few lessons learned:</p>
<h3 id="heading-let-xcode-extract-all-the-phrases-for-you">Let Xcode extract all the phrases for you</h3>
<p>Xcode has a menu command <strong>Product &gt; Export Localizations…</strong> that leverages the compiler to find translatable text and to produce a <strong>.xcloc</strong> file.<br />Opening that file will launch a nice table-based Xcode editor for translations.</p>
<h3 id="heading-translating-is-easier-when-the-keys-are-english-phrases">Translating is easier when the keys are English phrases</h3>
<p><code>Text(“Workouts”)</code> is better than <code>Text(workoutsTitleTranslation)</code> because it’s in place, it’s less code to write/maintain, and makes the .xcloc editor much more usable. Translators will always prefer reading English to processing abstractions.</p>
<h3 id="heading-translating-is-more-efficient-in-an-organized-workspace">Translating is more efficient in an organized workspace</h3>
<p>When you make the effort to organize phrases by <em>tables</em>, work in the .xcloc editor becomes more compartmentalized, focused and efficient. What you group up by is up to you: It can be phrases within a tab, a screen, a module, a feature... whatever makes sense: <code>Text(“Select all”, tableName: “Workouts tab”)</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1693040633525/b644f7fd-f14a-422e-9cfe-67e1fd9082ff.png" alt class="image--center mx-auto" /></p>
<p>However, organizing into tables in code comes with a gotcha: the parameter for <code>String(localized: table:)</code> is called <em>table,</em> but the SwiftUI team decided to call it <em>tableName</em> in <code>Text(_: tableName)</code>. It <strong>will</strong> be annoying throughout the process of updating your code, so you might want to extend one of those to match the signature of the other -- to your preference.</p>
<h3 id="heading-add-translation-comments-for-every-phrase">Add translation comments for every phrase</h3>
<p><code>Text(“This year”, comment: “Button; sets dates…”)</code><br />Writing "descriptions" for every translatable phrase might seem unnecessary and tedious, especially if you're the only person working on the codebase, but nothing could be further from the truth. These comments are not for you (although they might help future you). The comments give context to translators, both human and AI. They help translations make sense to users. And if you want to excel in these, learn best practices from this WWDC21 video: <a target="_blank" href="https://developer.apple.com/videos/play/wwdc2021/10221/">https://developer.apple.com/videos/play/wwdc2021/10221/</a></p>
<h3 id="heading-dont-forget-the-numbers">Don't forget the "numbers"</h3>
<p>Users expect to see dates and numbers appropriate for the language they are using the app in, so don't forget to set up formatters to render them. The Foundation framework already does so much of the heavy lifting for us, we pretty much just have to set up the templates.</p>
<hr />
<p>Localizing apps is much more than just topics mentioned in this article but I am hoping that these tips will help you hit the ground running. And if your main obstacle is finding the translators, I have another tip for you: check out <a target="_blank" href="https://strings.dev">Strings.dev</a> (I am not affiliated in any way).</p>
]]></content:encoded></item><item><title><![CDATA[error [PHPhotosErrorDomain] -1: The operation couldn’t be completed. (PHPhotosErrorDomain error -1.)]]></title><description><![CDATA[If you're seeing PHPhotosErrorDomain error -1 after attempting to add an image to Simulator via xcrun simctl addmedia <simulatorID> image.jpeg it might be because the image.jpeg is in a folder that is synced to your iCloud Drive.
Just copy the file t...]]></description><link>https://articles.danielkasaj.com/error-phphotoserrordomain-1-the-operation-couldnt-be-completed-phphotoserrordomain-error-1</link><guid isPermaLink="true">https://articles.danielkasaj.com/error-phphotoserrordomain-1-the-operation-couldnt-be-completed-phphotoserrordomain-error-1</guid><category><![CDATA[Xcode]]></category><category><![CDATA[simulator ]]></category><dc:creator><![CDATA[Daniel Kašaj]]></dc:creator><pubDate>Thu, 17 Aug 2023 16:54:08 GMT</pubDate><content:encoded><![CDATA[<p>If you're seeing <strong>PHPhotosErrorDomain error -1</strong> after attempting to add an image to Simulator via <code>xcrun simctl addmedia &lt;simulatorID&gt; image.jpeg</code> it might be because the <strong>image.jpeg is in a folder that is synced to your iCloud Drive</strong>.</p>
<p>Just copy the file to some other folder (which is not synced to iCloud Drive 😁) and add the media from there.</p>
]]></content:encoded></item><item><title><![CDATA[Extend Swift types with static parameters for reuse, consistency, and faster coding]]></title><description><![CDATA[I believe there comes a time when every developer adopts a technique for reusing common parameters. For years, I’ve been keeping all of my ”settings” in a single place i.e.

which I would use like:

label.textColor = GlobalSettings.darkRed

direction...]]></description><link>https://articles.danielkasaj.com/extend-swift-types-with-static-parameters-for-reuse-consistency-and-faster-coding</link><guid isPermaLink="true">https://articles.danielkasaj.com/extend-swift-types-with-static-parameters-for-reuse-consistency-and-faster-coding</guid><category><![CDATA[Swift]]></category><dc:creator><![CDATA[Daniel Kašaj]]></dc:creator><pubDate>Wed, 12 Jul 2023 06:11:52 GMT</pubDate><content:encoded><![CDATA[<p>I believe there comes a time when every developer adopts a technique for reusing common parameters. For years, I’ve been keeping all of my ”settings” in a single place i.e.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689141311472/fd8512ed-45aa-4d20-951d-f1a9fe57e982.png" alt class="image--center mx-auto" /></p>
<p>which I would use like:</p>
<ul>
<li><p><code>label.textColor = GlobalSettings.darkRed</code></p>
</li>
<li><p><code>directionalLayoutMargins = GlobalSettings.defaultMargins</code></p>
</li>
</ul>
<p><strong>But there is a better way.</strong></p>
<p>Extending individual types:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689141415783/571d63d3-38d8-45cc-8964-1565d8618eba.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689141428197/f970c738-8389-45a4-bd20-ea0883fa4897.png" alt class="image--center mx-auto" /></p>
<p>This makes coding so much easier and less verbose at the point of assigning - just start typing with a dot and rely on autocomplete to get to:</p>
<ul>
<li><p><code>label.textColor = .darkRed</code></p>
</li>
<li><p><code>directionalLayoutMargins = .defaultMargins</code></p>
</li>
</ul>
<p>And as a bonus, keeping these extensions in individual files reduces compile time. Remember GlobalSettings? Changing a single parameter in there would require every source file that references GlobalSettings to get recompiled.</p>
<p>--</p>
<p>Images above were generated with <a target="_blank" href="https://sebvidal.com/snippet">Snippet</a> built by <a target="_blank" href="https://twitter.com/sebjvidal">Seb Vidal</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Put Swift's Logger to good use: log everything & keep your console decluttered at the same time]]></title><description><![CDATA[Logger is an Apple framework available since Xcode 12 / iOS 14 and it’s the best way to track your app’s behavior.
It offers various levels of logging — info, warning, error, and more — which you sprinkle around your code so that you can monitor the ...]]></description><link>https://articles.danielkasaj.com/swift-logger-tutorial-good-practice</link><guid isPermaLink="true">https://articles.danielkasaj.com/swift-logger-tutorial-good-practice</guid><category><![CDATA[Swift]]></category><category><![CDATA[logging]]></category><dc:creator><![CDATA[Daniel Kašaj]]></dc:creator><pubDate>Fri, 23 Jun 2023 06:50:10 GMT</pubDate><content:encoded><![CDATA[<p><a target="_blank" href="https://developer.apple.com/documentation/os/logger">Logger</a> is an Apple framework available since Xcode 12 / iOS 14 and it’s the best way to track your app’s behavior.</p>
<p>It offers various levels of logging — info, warning, error, and more — which you sprinkle around your code so that you can monitor the flow in the console.</p>
<p>As your app grows, so does the volume of messages in the console.</p>
<p>Instead of filtering Xcode’s console by keywords or updating search parameters in the Console app, here’s how I keep my console de-cluttered:</p>
<ul>
<li><p>Have a Logger instance for each “subsystem” of the app</p>
</li>
<li><p>Explicitly define (and use it) as an optional</p>
</li>
<li><p>Manage which of them are active in a single place - a file that extends Logger</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687502833509/9f759180-fece-4fe4-8d6f-41ca6ff5aed8.png" alt class="image--center mx-auto" /></p>
<p>My code here shows that I want to keep seeing <em>health</em> and <em>shoes</em> messages, but <em>CoreData</em> and <em>onboarding</em> are not needed at this time -- I just set them to nil, and comment out the original code.</p>
<p>--</p>
<p>The image above was generated with <a target="_blank" href="https://sebvidal.com/snippet">Snippet</a> built by <a target="_blank" href="https://twitter.com/sebjvidal">Seb Vidal</a> and uses a background by the wonderfully creative <a target="_blank" href="https://twitter.com/MengTo">Meng To</a>.</p>
]]></content:encoded></item></channel></rss>