<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Snippets — FlineDev</title>
<description>Blog, apps, and open source Swift packages by indie developer Cihat Gündüz. Topics: SwiftUI, visionOS, error handling, localization, and more.</description>
<link>https://fline.dev/de/snippets/</link>
<language>de</language>
<atom:link href="https://fline.dev/de/snippets/feed.xml" rel="self" type="application/rss+xml"/>
<item>
<title>Vapors maximumActiveConnections gilt pro Event Loop, nicht pro Worker</title>
<link>https://fline.dev/de/snippets/vapor-maximum-active-connections/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/vapor-maximum-active-connections/</guid>
<pubDate>Mon, 29 Dec 2025 00:00:00 +0000</pubDate>
<description><![CDATA[Ein nicht offensichtliches Vapor-Konfigurationsdetail, das intermittierende 500-Fehler verursachen kann, wenn die tatsächliche Verbindungsanzahl das übersteigt, was du konfiguriert zu haben glaubst.]]></description>
<content:encoded><![CDATA[<h2 id="die-irreführende-konfiguration">Die irreführende Konfiguration</h2><p>Beim Konfigurieren von Connection Pools in Vapor – ob für Redis, PostgreSQL oder andere Datenbanken – begegnet dir ein Parameter namens <code>maximumActiveConnections</code>. Die naheliegende Annahme ist, dass dieser die maximale Gesamtanzahl an Verbindungen für deine Anwendung festlegt. Tut er nicht. Er legt das Maximum pro NIO <code>EventLoop</code> fest.</p><p>Diese Unterscheidung ist in der Produktion enorm wichtig.</p><h2 id="die-rechnung-die-mich-überrascht-hat">Die Rechnung, die mich überrascht hat</h2><p>Auf einem typischen Server erstellt Swift NIO einen <code>EventLoop</code> pro CPU-Kern. Die tatsächliche maximale Verbindungsanzahl ist also:</p><pre><code>actual max = maximumActiveConnections * CPU cores * number of dynos/instances</code></pre><p>Ich hatte <code>maximumActiveConnections</code> auf 8 gesetzt, in der Annahme, dass ich meine Redis-Verbindungen auf vernünftige 16 über zwei Dynos begrenze. Die tatsächliche Zahl:</p><pre><code>8 (per event loop) * 8 (cores) * 2 (dynos) = 128 potential connections</code></pre><p>Das ist eine Größenordnung mehr als beabsichtigt, und es überschritt das Verbindungslimit meines Redis-Anbieters bei Traffic-Spitzen.</p><p><img src="/assets/images/snippets/vapor-maximum-active-connections/code-screenshot.webp" alt="Code showing the connection pool configuration" loading="lazy" /></p><h2 id="die-symptome">Die Symptome</h2><p>Der Fehlermodus ist besonders tückisch: intermittierende 500-Fehler, die nur unter Last auftreten. Bei normalem Traffic erreichst du nie das echte Verbindungslimit, also funktioniert alles einwandfrei. Bei Spitzen häufen sich Verbindungen über alle Event Loops gleichzeitig an und überschreiten das Limit des Anbieters. Die Fehler wirken zufällig und sind lokal schwer zu reproduzieren, weil Entwicklungsmaschinen typischerweise weniger Kerne haben.</p><h2 id="den-richtigen-wert-berechnen">Den richtigen Wert berechnen</h2><p>Teile das Verbindungslimit deines Anbieters durch die Gesamtzahl der Event Loops über alle Instanzen hinweg:</p><pre><code class="language-swift">// Provider limit: 40 connections
// 2 dynos * 8 cores = 16 event loops total
// 40 / 16 = 2.5, round down to 2

app.redis.configuration = .init(
   pool: .init(maximumActiveConnections: 2)
)</code></pre><p>Diese konservative Einstellung hat endlich die seit Langem bestehenden seltenen 500-Fehler in TranslateKit behoben, die mich monatelang verwirrt hatten. Überprüfe immer die Verbindungslimits deines Cloud-Anbieters und rechne die Multiplikation durch, bevor du deployst.</p>]]></content:encoded>
</item>
<item>
<title>Apple setzt Feedback-Anfragen um – Bug-Reports einreichen lohnt sich</title>
<link>https://fline.dev/de/snippets/apple-implements-feedback-requests/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/apple-implements-feedback-requests/</guid>
<pubDate>Tue, 10 Jun 2025 00:00:00 +0000</pubDate>
<description><![CDATA[Eine persönliche Erfahrung, wie ein Feedback Assistant-Bericht in Xcode 26 umgesetzt wurde, und Tipps zum Schreiben effektiver Feedback-Berichte.]]></description>
<content:encoded><![CDATA[<h2 id="dein-feedback-wird-tatsächlich-gelesen">Dein Feedback wird tatsächlich gelesen</h2><p>Es gibt einen weit verbreiteten Glauben in der Entwickler-Community, dass das Einreichen von Feedback Assistant-Berichten (dem Nachfolger von Radar) sinnlos ist – dass Berichte in einem Loch verschwinden und nie etwas passiert. Ich hatte einen Feature-Request, der in Xcode 26 implementiert wurde, was das Gegenteil beweist.</p><p><img src="/assets/images/snippets/apple-implements-feedback-requests/feedback-implemented.webp" alt="Screenshot showing the implemented feedback request" loading="lazy" /></p><p>Zu sehen, wie ein Feature, das du angefragt hast, in einer Keynote oder Release Notes auftaucht, ist eine befriedigende Bestätigung. Aber noch wichtiger: Es zeigt, dass Apples Engineering-Teams Community-Feedback tatsächlich lesen und priorisieren, selbst wenn sie nie direkt auf den Bericht antworten.</p><h2 id="tipps-zum-schreiben-effektiven-feedbacks">Tipps zum Schreiben effektiven Feedbacks</h2><p>Nicht alle Berichte sind gleich. Hier ist, was nach meiner Erfahrung die Chancen erhöht, dass ein Bericht bearbeitet wird:</p><p><strong>Sei spezifisch mit dem Problem.</strong> „Xcode ist langsam” ist nicht hilfreich. „Xcodes SwiftUI Preview braucht 12 Sekunden zum Aktualisieren, wenn die Datei mehr als 3 <code>#Preview</code>-Blöcke enthält” gibt Ingenieuren etwas zum Untersuchen.</p><p><strong>Lege ein Beispielprojekt bei.</strong> Ein minimales Reproduktionsprojekt ist das wertvollste, was du anhängen kannst. Wenn ein Ingenieur dein Projekt bauen und starten kann, um das Problem zu sehen, hast du die größte Hürde zur Untersuchung beseitigt.</p><p><strong>Beschreibe den Anwendungsfall, nicht nur die Lösung.</strong> Anstatt „füge einen Button hinzu, der X macht”, erkläre, warum du es brauchst: „Beim Arbeiten mit großen SPM-Graphen muss ich schnell identifizieren, zu welchem Target eine Datei gehört, weil …” Das gibt dem Team Kontext, um die richtige Lösung zu entwickeln, die anders sein könnte als das, was du dir vorgestellt hast.</p><p><strong>Reiche während der Beta-Saison ein.</strong> Die Wochen nach der WWDC sind die Zeit, in der Apples Teams am aktivsten Feedback zu neuen Features sammeln. Berichte, die in diesem Zeitraum eingereicht werden, bekommen deutlich mehr Aufmerksamkeit als solche, die mitten im Release-Zyklus eingereicht werden.</p><h2 id="mach-es-zur-gewohnheit">Mach es zur Gewohnheit</h2><p>Nimm dir jede WWDC-Beta-Saison Zeit, deine Apps gegen die neuen OS- und Xcode-Betas zu testen. Reiche Berichte für jedes Problem und jedes fehlende Feature ein. Die meisten werden keine Antwort bekommen, aber einige werden stillschweigend zukünftige Releases beeinflussen.</p>]]></content:encoded>
</item>
<item>
<title>.labelStyle(.iconOnly) statt Image in Button verschachteln</title>
<link>https://fline.dev/de/snippets/labelstyle-icononly-swiftui/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/labelstyle-icononly-swiftui/</guid>
<pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate>
<description><![CDATA[Das richtige SwiftUI-Pattern für Icon-only Buttons, das die Barrierefreiheit bewahrt, ohne die Lesbarkeit zu opfern.]]></description>
<content:encoded><![CDATA[<h2 id="hör-auf-gegen-das-framework-zu-kämpfen">Hör auf, gegen das Framework zu kämpfen</h2><p>Ein Pattern, das ich ständig in SwiftUI-Code sehe, ist das manuelle Erstellen von Icon-only Buttons, indem ein <code>Image</code> direkt in die Label-Closure eines <code>Button</code> gepackt wird. Es funktioniert visuell, wirft aber Barrierefreiheits-Informationen weg und arbeitet gegen das Design von SwiftUI.</p><h2 id="der-falsche-weg">Der falsche Weg</h2><pre><code class="language-swift">Button {
   toggleSidebar()
} label: {
   Image(systemName: &quot;sidebar.left&quot;)
}</code></pre><p>Das rendert ein tippbares Icon, aber VoiceOver hat kein aussagekräftiges Label zum Vorlesen. Der Nutzer hört etwas wie „button” oder den rohen SF Symbol-Namen, was nicht hilfreich ist.</p><h2 id="der-richtige-weg">Der richtige Weg</h2><pre><code class="language-swift">Button(&quot;Toggle Sidebar&quot;, systemImage: &quot;sidebar.left&quot;) {
   toggleSidebar()
}
.labelStyle(.iconOnly)</code></pre><p>Oder mit explizitem <code>Label</code>:</p><pre><code class="language-swift">Button(action: toggleSidebar) {
   Label(&quot;Toggle Sidebar&quot;, systemImage: &quot;sidebar.left&quot;)
}
.labelStyle(.iconOnly)</code></pre><p><img src="/assets/images/snippets/labelstyle-icononly-swiftui/code-comparison.webp" alt="Code comparison showing the wrong way versus the right way" loading="lazy" /></p><h2 id="warum-das-wichtig-ist">Warum das wichtig ist</h2><p>Die <code>Label</code>-View trägt sowohl einen Titel als auch ein Icon. Wenn du <code>.labelStyle(.iconOnly)</code> anwendest, versteckt SwiftUI den Titel visuell, bewahrt ihn aber im Accessibility-Baum. VoiceOver liest „Toggle Sidebar, button” vor – genau das, was der Nutzer hören muss.</p><p>Dieses Pattern macht deinen Code auch anpassungsfähiger. Wenn du dich später entscheidest, Text neben dem Icon anzuzeigen (zum Beispiel in einer Toolbar auf dem iPad), änderst du einfach den Label-Style auf <code>.titleAndIcon</code>. Keine Umstrukturierung nötig.</p><h2 id="über-buttons-hinaus">Über Buttons hinaus</h2><p>Dasselbe Prinzip gilt für jede View, die ein <code>Label</code> akzeptiert: <code>NavigationLink</code>, <code>Toggle</code>, <code>Picker</code>, Menüeinträge. Wann immer du versucht bist, ein nacktes <code>Image</code> zu verwenden, frag dich, ob ein <code>Label</code> mit einem Style-Modifier nicht passender wäre. In fast jedem Fall ist es das.</p>]]></content:encoded>
</item>
<item>
<title>EditorConfig für jedes SwiftPM-Paket</title>
<link>https://fline.dev/de/snippets/editorconfig-swiftpm-package/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/editorconfig-swiftpm-package/</guid>
<pubDate>Tue, 03 Dec 2024 00:00:00 +0000</pubDate>
<description><![CDATA[Warum jedes Swift Package eine .editorconfig-Datei beinhalten sollte, um konsistente Einrückung bei allen Mitwirkenden durchzusetzen.]]></description>
<content:encoded><![CDATA[<h2 id="das-unsichtbare-formatierungsproblem">Das unsichtbare Formatierungsproblem</h2><p>Wenn mehrere Personen an einem Swift Package mitwirken, schleichen sich Einrückungs-Inkonsistenzen ein. Ein Mitwirkender nutzt 4 Leerzeichen, ein anderer Tabs, ein dritter 2 Leerzeichen. Pull Requests werden durch reine Whitespace-Änderungen unübersichtlich, und die Codebasis driftet in ein inkonsistentes Durcheinander. Die Lösung ist eine einzelne Datei, die in 30 Sekunden hinzugefügt ist.</p><h2 id="der-editorconfig-standard">Der .editorconfig-Standard</h2><p>EditorConfig ist ein weit verbreiteter Standard zur Definition von Coding-Style-Einstellungen pro Projekt. Xcode respektiert <code>.editorconfig</code>-Dateien, sodass Mitwirkende automatisch die korrekten Einrückungseinstellungen bekommen, wenn sie das Projekt öffnen – keine manuelle Konfiguration, keine Dokumentation zum Lesen.</p><p>Hier ist die <code>.editorconfig</code>, die ich für jedes SwiftPM Package empfehle:</p><pre><code>root = true

[*.swift]
indent_style = space
indent_size = 3

[*.{yml,yaml,json}]
indent_style = space
indent_size = 2</code></pre><p>Die 3-Leerzeichen-Einrückung für Swift ist eine bewusste Wahl. Sie ist weniger verbreitet als 2 oder 4 Leerzeichen, trifft aber einen Sweet Spot: besser lesbar als 2 Leerzeichen bei verschachtelten Closures, weniger Verschwendung von horizontalem Platz als 4 Leerzeichen. Wenn du es einmal ausprobierst, fühlen sich die Standard-Optionen entweder zu eng oder zu weit auseinander an.</p><h2 id="warum-das-globale-einstellungen-übertrifft">Warum das globale Einstellungen übertrifft</h2><p>Jeder Entwickler hat seine eigenen Xcode-Einrückungspräferenzen global konfiguriert. Ohne <code>.editorconfig</code> werden diese globalen Einstellungen auf jedes Projekt angewandt, das geöffnet wird. Das bedeutet, ein Mitwirkender mit 4-Leerzeichen-Tabs wird Code stillschweigend umformatieren, wenn er eine Datei bearbeitet, selbst wenn die Projektkonvention anders ist.</p><p>Mit <code>.editorconfig</code> im Repository-Root überschreibt Xcode die globalen Einstellungen mit den projektspezifischen. Mitwirkende müssen nichts ändern – es funktioniert einfach.</p><h2 id="einführung">Einführung</h2><p>Lege diese Datei in dein Package-Root und committe sie. Das ist alles. Es gibt keinen Build-Schritt, keine Abhängigkeit, keine Konfiguration über die Datei selbst hinaus. Die meisten modernen Editoren (VS Code, Vim, Sublime Text) unterstützen ebenfalls EditorConfig, sodass auch Nicht-Xcode-Mitwirkende profitieren.</p>]]></content:encoded>
</item>
<item>
<title>Push-Benachrichtigungen für App Store Reviews</title>
<link>https://fline.dev/de/snippets/push-notifications-app-store-reviews/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/push-notifications-app-store-reviews/</guid>
<pubDate>Thu, 28 Nov 2024 00:00:00 +0000</pubDate>
<description><![CDATA[Wie man Push-Benachrichtigungen für neue App Store Reviews in der App Store Connect App aktiviert, um schnell auf Nutzerfeedback reagieren zu können.]]></description>
<content:encoded><![CDATA[<h2 id="eine-versteckte-funktion-in-app-store-connect">Eine versteckte Funktion in App Store Connect</h2><p>Die App Store Connect iOS-App hat ein Feature, das die meisten Entwickler nie entdecken: Push-Benachrichtigungen für neue Nutzerbewertungen. Es ist standardmäßig deaktiviert, und du musst es für jede App separat aktivieren, was wahrscheinlich der Grund ist, warum so wenige Leute davon wissen.</p><h2 id="so-aktiviert-man-es">So aktiviert man es</h2><p>Öffne die App Store Connect App auf deinem iPhone und navigiere zu:</p><ol><li><p>Tippe auf dein Profilbild oder gehe zu <strong>Settings</strong></p></li><li><p>Wähle <strong>Notifications</strong></p></li><li><p>Du siehst eine Liste aller deiner Apps</p></li><li><p>Aktiviere für jede App <strong>Customer Reviews</strong></p></li></ol><p>Das war’s. Ab jetzt bekommst du eine Push-Benachrichtigung, wann immer jemand eine neue Bewertung für diese App hinterlässt.</p><p><video src="/assets/images/snippets/push-notifications-app-store-reviews/demo.mp4" controls muted playsinline></video></p><h2 id="warum-das-für-indie-entwickler-wichtig-ist">Warum das für Indie-Entwickler wichtig ist</h2><p>Schnell auf App Store Reviews zu reagieren hat einen spürbaren Einfluss. Wenn ein Nutzer eine negative Bewertung über einen Bug hinterlässt, kann eine schnelle Antwort, die das Problem anerkennt (oder auf einen Fix hinweist), dazu führen, dass er seine Bewertung aktualisiert. Positive Bewertungen verdienen ebenfalls Anerkennung – das ermutigt Nutzer, weiterhin Feedback zu geben.</p><p>Ohne Benachrichtigungen schauen die meisten Entwickler nur dann nach Bewertungen, wenn sie daran denken, was Tage oder Wochen später sein kann. Bis dahin hat der Nutzer weitergemacht, und deine Antwort wirkt wie ein nachträglicher Einfall.</p><h2 id="ein-wort-der-vorsicht">Ein Wort der Vorsicht</h2><p>Wenn du mehrere Apps mit hohem Bewertungsvolumen hast, könnte das Aktivieren für alle davon laut werden. Fang mit deinen wichtigsten Apps an und passe es an, basierend darauf, wie viele Benachrichtigungen du tatsächlich bekommst. Für die meisten Indie-Entwickler mit einer Handvoll Apps ist das Volumen gut handhabbar und die Vorteile sind sofort spürbar.</p>]]></content:encoded>
</item>
<item>
<title>Videos und Tabs in DocC-Dokumentationen</title>
<link>https://fline.dev/de/snippets/docc-videos-tabs-documentation/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/docc-videos-tabs-documentation/</guid>
<pubDate>Thu, 20 Jun 2024 00:00:00 +0000</pubDate>
<description><![CDATA[Zwei weniger bekannte DocC-Features, die deine Dokumentation interaktiver machen: eingebettete Videos und Navigation mit Tabs.]]></description>
<content:encoded><![CDATA[<h2 id="über-einfaches-markdown-in-docc-hinaus">Über einfaches Markdown in DocC hinaus</h2><p>Die meisten Entwickler wissen, dass DocC Standard-Markdown unterstützt, aber es gibt zwei mächtige Direktiven, die überraschend wenig genutzt werden: Video-Einbettung und Tab-Inhalte. Beide funktionieren in Xcodes Dokumentations-Viewer und auf gehosteten DocC-Websites.</p><h2 id="videos-einbetten">Videos einbetten</h2><p>Ein Video zur Dokumentation hinzuzufügen ist eine einzige Direktive:</p><pre><code>@Video(source: &quot;setup-walkthrough.mp4&quot;)</code></pre><p>Platziere die Videodatei im Resources-Ordner deines Dokumentationskatalogs. Das rendert einen Inline-Videoplayer direkt in der Dokumentation, was weitaus effektiver ist als auf eine externe URL zu verlinken oder einen visuellen Prozess in Text zu beschreiben. Es funktioniert gut für Setup-Guides, UI-Walkthroughs oder das Demonstrieren von Animationen.</p><h2 id="tab-inhalte-mit-tabnavigator">Tab-Inhalte mit TabNavigator</h2><p>Wenn du alternative Ansätze oder plattformspezifische Anleitungen zeigen musst, halten Tabs die Dinge übersichtlich, ohne den Leser zu überfordern:</p><pre><code>@TabNavigator {
   @Tab(&quot;SwiftUI&quot;) {
      Use the `.environment` modifier to inject dependencies.
   }
   @Tab(&quot;UIKit&quot;) {
      Override `viewDidLoad` and configure your dependencies there.
   }
}</code></pre><p>Das rendert als echtes Tab-Interface, bei dem Leser zwischen Abschnitten wechseln können. Es ist besonders nützlich für Dokumentation, die mehrere Plattformen, API-Versionen oder Konfigurationsansätze abdeckt.</p><p><video src="/assets/images/snippets/docc-videos-tabs-documentation/demo.mp4" controls muted playsinline></video></p><h2 id="praktische-hinweise">Praktische Hinweise</h2><p>Ich habe meinen Contributing-Guide aktualisiert, um beide Features zu nutzen, und das Ergebnis ist deutlich zugänglicher als eine Textwand. Das Video zeigt den Setup-Prozess, der Absätze zum Beschreiben brauchen würde, und die Tabs trennen plattformspezifische Schritte sauber.</p><p>Diese Direktiven sind in Apples <a href="https://www.swift.org/documentation/docc/video">DocC-Dokumentation</a> dokumentiert, werden aber selten in Tutorials erwähnt. Wenn du ein Open-Source Swift Package pflegst, überlege, sie deinem Dokumentationskatalog hinzuzufügen – sie machen einen echten Unterschied dabei, wie Leute deine Docs erleben.</p>]]></content:encoded>
</item>
<item>
<title>Kostenpflichtige Apps auf Freemium umstellen, ohne bestehende Nutzer zu benachteiligen</title>
<link>https://fline.dev/de/snippets/convert-paid-apps-freemium/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/convert-paid-apps-freemium/</guid>
<pubDate>Thu, 28 Mar 2024 00:00:00 +0000</pubDate>
<description><![CDATA[Wie man StoreKits AppTransaction API nutzt, um von kostenpflichtig zu Freemium zu wechseln und dabei den Zugang für Nutzer zu bewahren, die bereits bezahlt haben.]]></description>
<content:encoded><![CDATA[<h2 id="das-problem-beim-wechsel-von-kostenpflichtig-zu-freemium">Das Problem beim Wechsel von kostenpflichtig zu Freemium</h2><p>Eine bezahlte App auf Freemium umzustellen ist eine gängige Geschäftsentscheidung, bringt aber eine Fairness-Herausforderung mit sich: Nutzer, die bereits für die App bezahlt haben, sollten nicht plötzlich Features verlieren oder erneut zur Kasse gebeten werden. StoreKits <code>AppTransaction</code> API löst das sauber.</p><h2 id="apptransaction-zur-überprüfung-der-kaufhistorie-verwenden">AppTransaction zur Überprüfung der Kaufhistorie verwenden</h2><p>Der Schlüssel ist <code>AppTransaction.shared</code>, das Informationen über die ursprüngliche Transaktion deiner App liefert. Genauer gesagt sagt dir <code>originalAppVersion</code>, welche Version der App der Nutzer ursprünglich heruntergeladen hat. Wenn diese Version eine bezahlte Version war, weißt du, dass der Nutzer bereits bezahlt hat.</p><pre><code class="language-swift">import StoreKit

func shouldGrantFullAccess() async -&gt; Bool {
   do {
      let result = try await AppTransaction.shared
      if case .verified(let transaction) = result {
         let originalVersion = transaction.originalAppVersion
         // Version &quot;2.0&quot; was when the app went freemium
         if originalVersion.compare(&quot;2.0&quot;, options: .numeric) == .orderedAscending {
            return true // User purchased before freemium transition
         }
      }
   } catch {
      // Handle verification failure
   }
   return false
}</code></pre><p>Die Logik ist unkompliziert: Vergleiche die <code>originalAppVersion</code> des Nutzers mit der Version, bei der du den Freemium-Wechsel vorgenommen hast. Wenn die ursprüngliche Version vor der Änderung liegt, gewähre automatisch vollen Zugriff.</p><h2 id="wichtige-details">Wichtige Details</h2><p>Die <code>originalAppVersion</code> entspricht dem <code>CFBundleShortVersionString</code>-Wert zum Zeitpunkt des ursprünglichen Kaufs (oder Downloads bei kostenlosen Apps). Stelle sicher, dass du genau weißt, welche Versionsnummer deinen Übergangspunkt markiert.</p><p>Dieser Ansatz erfordert keine Server-Infrastruktur und keinen Migrationscode. StoreKit übernimmt die Verifizierung über die App Store Receipt Chain, sodass die Prüfung manipulationssicher ist. Apple dokumentiert dieses Muster in der <a href="https://developer.apple.com/documentation/storekit/apptransaction/3954437-originalappversion">Original-API für Geschäftsmodell-Migration</a>.</p><p>Für TestFlight- und Simulator-Tests gibt <code>originalAppVersion</code> stattdessen die <code>CFBundleVersion</code> (Build-Nummer) zurück, plane deine Testfälle also entsprechend.</p>]]></content:encoded>
</item>
<item>
<title>Xcode Quick Help in der Seitenleiste</title>
<link>https://fline.dev/de/snippets/xcode-quick-help-sidebar/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/xcode-quick-help-sidebar/</guid>
<pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate>
<description><![CDATA[Der Quick Help Inspector in Xcodes Sidebar aktualisiert die Dokumentation automatisch bei Cursorbewegungen, ohne dass man für Docs Cmd-klicken muss.]]></description>
<content:encoded><![CDATA[<h2 id="eine-übersehene-funktion">Eine übersehene Funktion</h2><p>Jahrelang war mein Workflow zum Nachschlagen von Dokumentation in Xcode derselbe: Cmd-Klick auf ein Symbol, „Show Quick Help” aus dem Kontextmenü wählen, das Popup lesen, dann schließen und weitercodieren. Es funktioniert, aber es unterbricht – jede Suche erfordert drei Aktionen und bricht deinen Arbeitsfluss.</p><p>Dann habe ich zufällig das Quick Help Inspector-Panel in der rechten Sidebar entdeckt.</p><p><video src="/assets/images/snippets/xcode-quick-help-sidebar/demo.mp4" controls muted playsinline></video></p><h2 id="so-funktioniert-es">So funktioniert es</h2><p>Öffne den Quick Help Inspector mit Option+Cmd+3 oder gehe zu View &gt; Inspectors &gt; Quick Help. Das öffnet ein Panel in der rechten Sidebar, das Dokumentation für das Symbol anzeigt, auf dem sich dein Cursor gerade befindet. Wenn du deinen Cursor durch den Code bewegst – auf eine Methode klickst, durch Parameter navigierst, einen Typ auswählst – aktualisiert sich die Sidebar automatisch.</p><p>Kein Klicken, kein Popup zum Schließen, keine Unterbrechung. Du codierst einfach weiter und die relevante Dokumentation folgt dir.</p><h2 id="warum-es-cmd-klick-übertrifft">Warum es Cmd-Klick übertrifft</h2><p>Der Cmd-Klick-Ansatz hat einen bestimmten Nachteil: Er erfordert, dass du entscheidest „Ich brauche Docs dafür”, bevor du nachschaust. Die Sidebar kehrt das um. Weil sie immer sichtbar ist, nimmst du Dokumentation passiv auf. Du bemerkst Parameterbeschreibungen, Rückgabetypen, Deprecation-Warnungen und Verfügbarkeitsannotationen, ohne bewusst danach suchen zu müssen.</p><p>Das ist besonders wertvoll beim Arbeiten mit unbekannten APIs. Anstatt bei jedem zweiten Symbol Cmd zu klicken, bewegst du einfach deinen Cursor durch den Code und liest die Sidebar nebenbei. Es verwandelt das Nachschlagen von Dokumentation von einer einzelnen Aktion in einen kontinuierlichen Strom.</p><p>Das Panel zeigt denselben Inhalt wie das Quick Help-Popup: Deklaration, Beschreibung, Parameter, Rückgabewert, Verfügbarkeit und verwandte Symbole. Der einzige Unterschied ist, dass es bestehen bleibt und sich an Ort und Stelle aktualisiert, anstatt zu erscheinen und zu verschwinden.</p><p>Wenn du den Platz für die rechte Sidebar hast, ist das Offenhalten von Quick Help beim Codieren eine dieser kleinen Workflow-Änderungen, die sich über die Zeit summieren.</p>]]></content:encoded>
</item>
<item>
<title>Einen AsyncButton in SwiftUI bauen</title>
<link>https://fline.dev/de/snippets/asyncbutton-swiftui-progress-status/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/asyncbutton-swiftui-progress-status/</guid>
<pubDate>Wed, 27 Sep 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Eine wiederverwendbare Button-Komponente, die asynchrone Aktionen mit automatischem Ladezustand, Deaktivierung und Erfolgs-/Fehleranzeige behandelt.]]></description>
<content:encoded><![CDATA[<h2 id="warum-asyncbutton-gebraucht-wird">Warum AsyncButton gebraucht wird</h2><p>Standard-SwiftUI-<code>Button</code>-Aktionen sind synchron. Wenn du eine asynchrone Operation durchführen musst – eine Netzwerkanfrage, einen Datenbankschreibvorgang, einen StoreKit-Kauf – musst du manuell einen <code>Task</code> verwalten, den Ladezustand tracken, den Button deaktivieren und Fehler behandeln. Dieses Boilerplate wiederholt sich bei jedem asynchronen Button in deiner App.</p><p>Ich habe eine <code>AsyncButton</code>-Komponente gebaut, die all das in eine einzige wiederverwendbare View verpackt.</p><p><video src="/assets/images/snippets/asyncbutton-swiftui-progress-status/demo.mp4" controls muted playsinline></video></p><h2 id="eine-vereinfachte-implementierung">Eine vereinfachte Implementierung</h2><p>Hier ist die Kernidee:</p><pre><code class="language-swift">struct AsyncButton&lt;Label: View&gt;: View {
   let action: () async throws -&gt; Void
   let label: () -&gt; Label

   @State private var isRunning = false
   @State private var result: Result&lt;Void, Error&gt;?

   var body: some View {
      Button {
         isRunning = true
         Task {
            do {
               try await action()
               result = .success(())
            } catch {
               result = .failure(error)
            }
            isRunning = false
         }
      } label: {
         HStack(spacing: 8) {
            label()
            if isRunning {
               ProgressView()
            }
         }
      }
      .disabled(isRunning)
   }
}</code></pre><p>Der Button erstellt intern einen <code>Task</code>, sodass Aufrufer <code>await</code> direkt in der Action-Closure verwenden können. Während der Task läuft, erscheint ein <code>ProgressView</code> neben dem Label und der Button wird deaktiviert, um doppelte Absendungen zu verhindern. Der <code>result</code>-State kann Erfolgs- oder Fehlerindikatoren steuern – ein Häkchen, einen Farbblitz oder eine Schüttelanimation.</p><h2 id="verwendung">Verwendung</h2><p>Die Verwendung fühlt sich natürlich an:</p><pre><code class="language-swift">AsyncButton {
   try await viewModel.submitOrder()
} label: {
   Text(&quot;Place Order&quot;)
}</code></pre><p>Kein manuelles State-Management, keine <code>Task</code>-Erstellung an der Aufrufstelle. Die vollständige Implementierung in <a href="https://github.com/FlineDev/HandySwiftUI">HandySwiftUI</a> fügt konfigurierbare Erfolgs-/Fehleranimationen, anpassbare Fortschrittsanzeigen und Unterstützung für Button-Styles hinzu. Aber das Kernmuster oben deckt den häufigsten Fall ab und lässt sich unkompliziert an deine eigenen Projekte anpassen.</p>]]></content:encoded>
</item>
<item>
<title>ImageRenderer kann UIKit-basierte Views nicht exportieren</title>
<link>https://fline.dev/de/snippets/imagerenderer-uikit-backed-views/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/imagerenderer-uikit-backed-views/</guid>
<pubDate>Tue, 19 Sep 2023 00:00:00 +0000</pubDate>
<description><![CDATA[SwiftUI's ImageRenderer versagt stillschweigend bei Views, die unter der Haube UIKit oder AppKit verwenden, wie List und ScrollView.]]></description>
<content:encoded><![CDATA[<h2 id="die-einschränkung">Die Einschränkung</h2><p>SwiftUI’s <code>ImageRenderer</code> ermöglicht es dir, jede SwiftUI View in ein <code>UIImage</code> oder <code>CGImage</code> zu rendern. Es funktioniert gut für reine SwiftUI Views, versagt aber stillschweigend – erzeugt ein leeres oder unvollständiges Bild – wenn der View-Baum Komponenten enthält, die von UIKit oder AppKit unterstützt werden. Das betrifft mehrere häufig verwendete Views:</p><ul><li><p><code>List</code> (umhüllt UITableView / NSTableView)</p></li><li><p><code>ScrollView</code> (umhüllt UIScrollView / NSScrollView)</p></li><li><p><code>TextEditor</code> (umhüllt UITextView / NSTextView)</p></li><li><p><code>Map</code> (umhüllt MKMapView)</p></li></ul><p>Es gibt weder eine Compiler-Warnung noch einen Runtime-Fehler. Der Renderer erfasst diese Teile der View-Hierarchie einfach nicht.</p><h2 id="der-workaround">Der Workaround</h2><p>Als ich ein listenähnliches Layout als Bild exportieren musste, bestand die Lösung darin, <code>List</code> durch ein reines SwiftUI-Äquivalent aus <code>VStack</code> und manueller Stilisierung zu ersetzen:</p><pre><code class="language-swift">let exportView = VStack(spacing: 0) {
   ForEach(items) { item in
      HStack {
         Text(item.name)
         Spacer()
         Text(item.value)
            .foregroundStyle(.secondary)
      }
      .padding(.horizontal, 16)
      .padding(.vertical, 12)

      if item.id != items.last?.id {
         Divider()
      }
   }
}
.background(.white)
.frame(width: 390)

let renderer = ImageRenderer(content: exportView)
renderer.scale = UIScreen.main.scale

if let image = renderer.uiImage {
   // Use the rendered image
}</code></pre><p>Der <code>VStack</code> mit <code>ForEach</code> repliziert die visuelle Struktur einer <code>List</code>, ohne auf UIKit-gestützte Views angewiesen zu sein. Das Hinzufügen von Dividers, Padding und einem Hintergrund erzeugt ein Ergebnis, das für Exportzwecke einer Standard-Liste nahe genug kommt.</p><h2 id="praktischer-ratschlag">Praktischer Ratschlag</h2><p>Wenn du vorhast, <code>ImageRenderer</code> in deiner App zu verwenden, designe deine exportierbaren Views mit dieser Einschränkung von Anfang an im Hinterkopf. Baue sie aus grundlegenden SwiftUI-Primitiven: Stacks, Text, Shapes und Images. Vermeide jede View, von der du weißt, dass sie ein plattformspezifisches Control umhüllt. Das Render-Ergebnis frühzeitig zu testen erspart die Frustration, später leere Bereiche zu entdecken.</p>]]></content:encoded>
</item>
<item>
<title>Swift-Imports mit einem Wrapper-Modul zusammenfassen</title>
<link>https://fline.dev/de/snippets/combine-swift-imports-wrapper-module/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/combine-swift-imports-wrapper-module/</guid>
<pubDate>Wed, 13 Sep 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Erstelle einen einzelnen Import, der alle häufig genutzten Frameworks mit @_exported import re-exportiert.]]></description>
<content:encoded><![CDATA[<h2 id="das-problem-der-sich-wiederholenden-imports">Das Problem der sich wiederholenden Imports</h2><p>In jedem Swift-Projekt mittlerer Größe hast du am Anfang fast jeder Datei denselben Satz an Imports. Foundation, SwiftUI, OSLog, vielleicht Observation – die Liste wächst, wenn du neue Frameworks übernimmst. Mit dem Wechsel zu strukturiertem Logging via OSLog habe ich festgestellt, dass ich <code>import OSLog</code> in fast jeder Datei neben den üblichen Verdächtigen hinzufüge.</p><p>Die Lösung ist ein Wrapper-Modul, das alles, was du häufig brauchst, über einen einzigen Import re-exportiert.</p><h2 id="das-wrapper-modul-einrichten">Das Wrapper-Modul einrichten</h2><p>Erstelle ein neues Target in deinem Swift Package oder Xcode-Projekt. In meinem Fall habe ich es <code>AppFoundation</code> genannt. Das gesamte Modul besteht aus einer einzigen Datei:</p><pre><code class="language-swift">// Sources/AppFoundation/Exports.swift
@_exported import Foundation
@_exported import SwiftUI
@_exported import OSLog
@_exported import Observation</code></pre><p>Das <code>@_exported</code>-Attribut macht alle öffentlichen Symbole jedes Frameworks für jede Datei verfügbar, die <code>AppFoundation</code> importiert. Jetzt braucht jede Datei in deiner App nur noch:</p><pre><code class="language-swift">import AppFoundation</code></pre><p>In deiner <code>Package.swift</code> hat das Target keinen eigenen Quellcode über die Exports-Datei hinaus. Dein App-Target deklariert eine Abhängigkeit von <code>AppFoundation</code>, und alle re-exportierten Frameworks werden überall verfügbar.</p><h2 id="zu-berücksichtigende-kompromisse">Zu berücksichtigende Kompromisse</h2><p>Dieser Ansatz hat klare Vorteile: weniger Boilerplate, weniger Merge-Konflikte in Import-Abschnitten und eine zentrale Stelle, um neue Framework-Imports hinzuzufügen. Aber es gibt Kompromisse.</p><p>Erstens ist <code>@_exported</code> ein unterstrichenes Attribut, was bedeutet, dass es nicht offiziell Teil der stabilen Swift-API ist. In der Praxis ist es seit Jahren stabil und wird im Ökosystem weit verbreitet verwendet, aber es gibt keine formale Garantie.</p><p>Zweitens können implizite Abhängigkeiten es schwerer machen zu verstehen, was eine Datei tatsächlich nutzt. Wenn jede Datei Zugriff auf alles hat, verlierst du den Dokumentationswert expliziter Imports. Wenn du später ein Modul in ein eigenständiges Package extrahierst, musst du die expliziten Imports wieder hinzufügen.</p><p>Für App-Targets, bei denen Bequemlichkeit wichtiger ist als strikte Modularität, spart das Wrapper-Modul-Pattern echte Zeit. Für wiederverwendbare Bibliotheken bleiben explizite Imports die bessere Wahl.</p>]]></content:encoded>
</item>
<item>
<title>SwiftUI Navigation: Daten präsentieren, nicht Views</title>
<link>https://fline.dev/de/snippets/swiftui-navigation-present-data/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/swiftui-navigation-present-data/</guid>
<pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Den Denkwechsel von imperativer Navigation in UIKit zu datengetriebener Navigation in SwiftUI verstehen.]]></description>
<content:encoded><![CDATA[<h2 id="der-denkmodellwechsel">Der Denkmodellwechsel</h2><p>In UIKit ist Navigation imperativ. Du sagst dem System genau, was es tun soll:</p><pre><code class="language-swift">let detailVC = DetailViewController()
detailVC.item = selectedItem
navigationController?.pushViewController(detailVC, animated: true)</code></pre><p>Du erstellst einen View Controller, konfigurierst ihn und pushst ihn auf den Stack. Du hast die Kontrolle über die Aktion.</p><p>SwiftUI funktioniert anders. Du navigierst nicht – du präsentierst Daten in neuen Views. Alles ist datengetrieben. Du kontrollierst keine Views. Du kontrollierst Daten.</p><h2 id="datengetriebene-navigation-in-der-praxis">Datengetriebene Navigation in der Praxis</h2><p>Mit <code>NavigationStack</code> wird Navigation durch State gesteuert. Du deklarierst, welche Daten welcher View zugeordnet werden, und SwiftUI kümmert sich um die Übergänge:</p><pre><code class="language-swift">struct ContentView: View {
   @State private var path: [Item] = []

   var body: some View {
      NavigationStack(path: $path) {
         List(items) { item in
            Button(item.name) {
               path.append(item)  // Modify data, not views
            }
         }
         .navigationDestination(for: Item.self) { item in
            DetailView(item: item)
         }
      }
   }
}</code></pre><p>Die Schlüsselzeile ist <code>path.append(item)</code>. Du pushst keine View. Du fügst Daten zu einem Array hinzu. SwiftUI beobachtet die Änderung und präsentiert die entsprechende View automatisch.</p><h2 id="warum-das-wichtig-ist">Warum das wichtig ist</h2><p>Diese Unterscheidung ist nicht nur philosophisch – sie hat praktische Konsequenzen. Weil Navigation State ist, bekommst du Deep Linking geschenkt, indem du das richtige Path-Array konstruierst. Du kannst den Navigationszustand persistieren und wiederherstellen, indem du den Pfad speicherst. Du kannst programmatisch zu jeder Tiefe navigieren, indem du mehrere Elemente auf einmal hinzufügst.</p><p>Es bedeutet auch, dass das Schließen einfach das Entfernen von Daten ist. <code>path.removeLast()</code> aufzurufen poppt die oberste View. Das Array zu leeren kehrt zum Root zurück. Kein Bedarf, View-Controller-Referenzen zu tracken oder die Navigationshierarchie zu durchlaufen.</p><p>Der Umstieg braucht Zeit zur Verinnerlichung, besonders wenn du jahrelange UIKit-Erfahrung hast. Aber sobald es Klick macht, wird SwiftUI-Navigation deutlich vorhersagbarer. Deine Views werden zu reinen Funktionen deiner Daten, und Navigation ist einfach ein weiteres Stück dieser Daten.</p>]]></content:encoded>
</item>
<item>
<title>AsyncImage unterstützt .resizable() nicht</title>
<link>https://fline.dev/de/snippets/asyncimage-resizable-modifier/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/asyncimage-resizable-modifier/</guid>
<pubDate>Wed, 26 Jul 2023 00:00:00 +0000</pubDate>
<description><![CDATA[SwiftUI's AsyncImage erlaubt den .resizable()-Modifier nicht, was einen phasenbasierten Workaround erfordert.]]></description>
<content:encoded><![CDATA[<h2 id="das-problem">Das Problem</h2><p>SwiftUI’s <code>AsyncImage</code> ist praktisch zum Laden von Remote-Bildern, hat aber eine überraschende Einschränkung: Du kannst den <code>.resizable()</code>-Modifier nicht darauf anwenden. Dieser Code kompiliert, verhält sich aber nicht wie erwartet:</p><pre><code class="language-swift">// This does NOT work as intended
AsyncImage(url: imageURL)
   .resizable()  // Has no effect -- AsyncImage is not an Image
   .aspectRatio(contentMode: .fill)
   .frame(width: 200, height: 200)</code></pre><p>Der Grund ist, dass <code>AsyncImage</code> kein <code>Image</code> ist – es ist eine Container-View, die den Ladezustand verwaltet. Der <code>.resizable()</code>-Modifier ist nur auf <code>Image</code> definiert, sodass die Anwendung auf <code>AsyncImage</code> nur die generische <code>View</code>-Version aufruft, die nichts Nützliches tut.</p><h2 id="die-lösung">Die Lösung</h2><p>Die Lösung ist die Verwendung des phasenbasierten Initializers, der dir direkten Zugriff auf den zugrunde liegenden <code>Image</code>-Wert gibt, sobald das Laden abgeschlossen ist:</p><pre><code class="language-swift">AsyncImage(url: imageURL) { phase in
   switch phase {
   case .success(let image):
      image
         .resizable()
         .aspectRatio(contentMode: .fill)
   case .failure:
      Image(systemName: &quot;photo&quot;)
         .foregroundStyle(.secondary)
   case .empty:
      ProgressView()
   @unknown default:
      EmptyView()
   }
}
.frame(width: 200, height: 200)
.clipped()</code></pre><p>Innerhalb des <code>.success</code>-Falls ist <code>image</code> ein echter <code>Image</code>-Wert, sodass <code>.resizable()</code> korrekt funktioniert. Das gibt dir auch Kontrolle über die Lade- und Fehlerzustände, was ohnehin die bessere Praxis ist.</p><h2 id="wann-man-manuell-lädt">Wann man manuell lädt</h2><p>Wenn du die rohen Bilddaten brauchst – zum Beispiel um sie zu cachen, ihre Größe zu prüfen oder ein <code>UIImage</code> zu erstellen – möchtest du <code>AsyncImage</code> vielleicht ganz überspringen und mit <code>URLSession</code> laden. Aber für die meisten reinen Anzeigefälle deckt der phasenbasierte Initializer den Bedarf ohne zusätzliche Komplexität.</p><p>Das ist eine dieser SwiftUI-APIs, bei denen der einfache Initializer verlockend aussieht, aber in der Praxis zu kurz greift. Verwende standardmäßig die phasenbasierte Version, wann immer du bildspezifische Modifier brauchst.</p>]]></content:encoded>
</item>
<item>
<title>Mehrzeiliger Code mit Ctrl+M in Xcode 15</title>
<link>https://fline.dev/de/snippets/multi-line-code-ctrl-m-xcode-15/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/multi-line-code-ctrl-m-xcode-15/</guid>
<pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Xcode 15 führt ein Ctrl+M-Tastenkürzel ein, um Funktionsaufrufe und Parameter auf mehrere Zeilen zu verteilen.]]></description>
<content:encoded><![CDATA[<h2 id="code-auf-mehrere-zeilen-aufteilen">Code auf mehrere Zeilen aufteilen</h2><p>Xcode 15 hat ein kleines, aber wirkungsvolles Tastenkürzel eingeführt: Ctrl+M. Setze deinen Cursor auf einen Funktionsaufruf, Initializer oder eine beliebige kommagetrennte Parameterliste, drücke Ctrl+M, und Xcode verteilt es automatisch auf mehrere Zeilen – ein Parameter pro Zeile, korrekt eingerückt.</p><p><img src="/assets/images/snippets/multi-line-code-ctrl-m-xcode-15/ctrl-m-shortcut.webp" alt="Ctrl+M shortcut" loading="lazy" /></p><p>Vor diesem Tastenkürzel bedeutete das Umformatieren eines langen Funktionsaufrufs manuelles Hinzufügen von Zeilenumbrüchen und Korrigieren der Einrückung. Betrachte einen Aufruf wie diesen:</p><pre><code class="language-swift">let label = UILabel(frame: .zero, font: .systemFont(ofSize: 14), textColor: .label, numberOfLines: 0)</code></pre><p>Nach dem Drücken von Ctrl+M mit dem Cursor auf dieser Zeile formatiert Xcode es um zu:</p><pre><code class="language-swift">let label = UILabel(
   frame: .zero,
   font: .systemFont(ofSize: 14),
   textColor: .label,
   numberOfLines: 0
)</code></pre><h2 id="wann-man-es-verwendet">Wann man es verwendet</h2><p>Dieses Tastenkürzel ist am wertvollsten, wenn du SwiftUI View Modifier oder Initializer schreibst, die im Laufe der Zeit Parameter ansammeln. Eine View, die mit zwei Parametern beginnt, wächst oft auf fünf oder sechs, wenn du Konfiguration hinzufügst. Anstatt jedes Mal manuell umzuformatieren, erledigt Ctrl+M das mit einem einzigen Tastendruck.</p><p>Es funktioniert auch umgekehrt – wenn deine Parameter bereits auf separaten Zeilen stehen, faltet Ctrl+M sie zurück in eine einzelne Zeile. Dieses Umschaltverhalten macht es einfach, je nach Lesbarkeitsbedarf zwischen kompaktem und erweitertem Format zu wechseln.</p><p>Ein Hinweis: Das Tastenkürzel arbeitet mit der innersten Parameterliste an der Cursorposition. Wenn du verschachtelte Funktionsaufrufe hast, positioniere deinen Cursor sorgfältig, um den richtigen zu erweitern.</p>]]></content:encoded>
</item>
<item>
<title>Apple-Dokumentation mit Shift+Cmd+O durchsuchen</title>
<link>https://fline.dev/de/snippets/search-apple-documentation-shift-cmd-o/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/search-apple-documentation-shift-cmd-o/</guid>
<pubDate>Sat, 10 Jun 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Nutze dasselbe Open Quickly-Tastenkürzel, um Apples Entwicklerdokumentation direkt im Web zu durchsuchen.]]></description>
<content:encoded><![CDATA[<h2 id="open-quickly-für-dokumentation">Open Quickly für Dokumentation</h2><p>Die meisten Xcode-Nutzer kennen Shift+Cmd+O – das „Open Quickly”-Tastenkürzel, mit dem du zu jeder Datei, jedem Symbol oder Typ in deinem Projekt springen kannst. Es ist eines dieser Tastenkürzel, das innerhalb von Tagen zur zweiten Natur wird. Was ich bis vor Kurzem nicht wusste: dasselbe Tastenkürzel funktioniert jetzt auch auf der Apple Developer Documentation Website, angetrieben von DocC.</p><p><img src="/assets/images/snippets/search-apple-documentation-shift-cmd-o/search-documentation.webp" alt="Search documentation" loading="lazy" /></p><p>Wenn du auf <a href="https://developer.apple.com/documentation">developer.apple.com/documentation</a> surfst, öffnet Shift+Cmd+O ein Such-Overlay, das sich genau wie Xcodes Open Quickly-Dialog verhält. Du kannst einen Framework-Namen, eine Klasse, eine Methode oder sogar eine Teilübereinstimmung eingeben, und Ergebnisse erscheinen sofort. Durch Auswahl eines Ergebnisses navigierst du direkt zu dieser Dokumentationsseite.</p><h2 id="warum-das-wichtig-ist">Warum das wichtig ist</h2><p>Vor diesem Feature bedeutete das Durchsuchen von Apples Dokumentation, durch die Sidebar-Hierarchie zu scrollen oder die allgemeine Suchleiste zu verwenden, die oft eine Mischung aus Artikeln, Tutorials und API-Referenzen lieferte. Das Open Quickly-Overlay filtert Ergebnisse auf API-Symbole und Seiten, was es deutlich präziser macht.</p><p>Das ist besonders nützlich, wenn du im Browser einen WWDC-Artikel oder Forum-Thread liest und schnell die Signatur einer verwandten API nachschlagen musst. Anstatt zurück zu Xcode zu wechseln, bleibst du im Kontext und schlägst es direkt nach.</p><p>Das Feature ist Teil von Apples breiterer Investition in DocC als Dokumentationsplattform. Da DocC sowohl Xcodes Dokumentations-Viewer als auch die webbasierte Dokumentation antreibt, ist es sinnvoll, dass dieselben Interaktionsmuster übernommen werden. Wenn du viel Zeit mit dem Lesen von Apple-Dokumentation im Browser verbringst, lohnt es sich, dieses Tastenkürzel in dein Muskelgedächtnis aufzunehmen.</p>]]></content:encoded>
</item>
<item>
<title>Xcode 15 bringt typsicheren Zugriff auf Asset Catalogs</title>
<link>https://fline.dev/de/snippets/xcode-15-type-safe-asset-catalogs/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/xcode-15-type-safe-asset-catalogs/</guid>
<pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Xcode 15 generiert typsichere Swift-Accessoren für Bilder und Farben in Asset Catalogs und ersetzt damit die Notwendigkeit für SwiftGen.]]></description>
<content:encoded><![CDATA[<h2 id="das-ende-von-string-basierten-asset-referenzen">Das Ende von String-basierten Asset-Referenzen</h2><p>Eine der stilleren, aber wirkungsvollen Änderungen in Xcode 15 ist der eingebaute typsichere Zugriff auf Asset Catalogs. Zuvor erforderte das Referenzieren eines Bildes oder einer Farbe aus dem Asset Catalog ein String-Literal:</p><pre><code class="language-swift">// Before Xcode 15
Image(&quot;custom-header-icon&quot;)
Color(&quot;primaryBrand&quot;)</code></pre><p>Das war fragil. Benenne ein Asset um und dein Code kompiliert einwandfrei, stürzt aber zur Laufzeit ab oder zeigt nichts an. Tools wie SwiftGen existierten speziell dafür, dieses Problem zu lösen, indem sie typsichere Konstanten aus deinen Asset Catalogs generierten.</p><h2 id="was-sich-geändert-hat">Was sich geändert hat</h2><p>Xcode 15 generiert jetzt automatisch Swift-Accessoren für jedes Bild und jede Farbe in deinem Asset Catalog. Du greifst über die Resource-Initializer darauf zu:</p><pre><code class="language-swift">// Xcode 15+
Image(.customHeaderIcon)
Color(.primaryBrand)</code></pre><p><img src="/assets/images/snippets/xcode-15-type-safe-asset-catalogs/asset-catalog-autocomplete.webp" alt="Xcode showing autocomplete suggestions for asset catalog resources" loading="lazy" /></p><p>Der Compiler kennt deine Assets. Du bekommst volle Autovervollständigung, und wenn du ein Asset löschst oder umbenennst, erhältst du einen Compile-Time-Fehler statt eines stillen Runtime-Fehlers.</p><h2 id="apple-hat-swiftgen-sherlocked">Apple hat SwiftGen sherlocked</h2><p>Das ist im Grunde Apple, das integriert, was SwiftGen seit Jahren bietet. Für Teams, die bereits SwiftGen verwenden, ist jetzt ein guter Zeitpunkt, zu evaluieren, ob es noch benötigt wird. Die eingebaute Lösung deckt die zwei häufigsten Anwendungsfälle ab – Bilder und Farben – ohne Build-Phase-Scripts oder Code-Generierungsschritte.</p><p>Es gibt weiterhin Gründe, SwiftGen zu behalten, wenn du es für Fonts, lokalisierte Strings oder andere Ressourcentypen nutzt. Aber für Asset Catalogs im Speziellen ist die native Lösung jetzt für die meisten Projekte gut genug und funktioniert sofort ohne Konfiguration.</p>]]></content:encoded>
</item>
<item>
<title>Xcode 15 String Catalogs ersetzen .strings und .stringsdict</title>
<link>https://fline.dev/de/snippets/xcode-15-string-catalogs/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/xcode-15-string-catalogs/</guid>
<pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Xcode 15 führt String Catalogs ein, einen visuellen Editor zur Verwaltung lokalisierter Strings, der die alten .strings- und .stringsdict-Dateien ersetzt.]]></description>
<content:encoded><![CDATA[<h2 id="der-bisherige-lokalisierungs-workflow">Der bisherige Lokalisierungs-Workflow</h2><p>Die Arbeit mit <code>.strings</code>- und <code>.stringsdict</code>-Dateien war schon immer eine der raueren Kanten der Apple-Entwicklung. Einfache Textdateien mit Schlüssel-Wert-Paaren sind fehleranfällig – fehlende Semikolons, nicht übereinstimmende Schlüssel zwischen Sprachen, keine Möglichkeit, den Übersetzungsfortschritt auf einen Blick zu sehen. Und <code>.stringsdict</code>-Dateien, die für Pluralisierungsregeln verwendet werden, sind XML-basierte Plist-Dateien, die bekanntermaßen schwierig von Hand zu erstellen sind.</p><h2 id="was-string-catalogs-mitbringen">Was String Catalogs mitbringen</h2><p>Xcode 15 führt ein neues <code>.xcstrings</code>-Dateiformat namens String Catalogs ein. Es ersetzt sowohl <code>.strings</code> als auch <code>.stringsdict</code> durch eine einzige Datei, die mit einem eigenen visuellen Editor kommt.</p><p><img src="/assets/images/snippets/xcode-15-string-catalogs/string-catalog-editor.webp" alt="The String Catalog editor in Xcode 15 showing translations across multiple languages" loading="lazy" /></p><p>Die wichtigsten Verbesserungen sind erheblich:</p><p><strong>Visueller Editor</strong> – Alle lokalisierbaren Strings werden in einer Tabelle mit Spalten für jede Sprache angezeigt. Du kannst Übersetzungen inline sehen und bearbeiten, ohne zwischen Dateien zu wechseln oder externe Tools zu verwenden.</p><p><strong>Übersetzungsfortschrittsverfolgung</strong> – Jede Sprache zeigt einen Fertigstellungsprozentsatz. Auf einen Blick kannst du erkennen, welche Sprachen Aufmerksamkeit brauchen und welche Strings noch unübersetzt sind.</p><p><strong>Automatische String-Extraktion</strong> – Xcode durchsucht deinen Swift-Code und entdeckt automatisch Strings, die lokalisiert werden müssen. Neue Strings erscheinen im Katalog ohne manuellen Registrierungsschritt.</p><p><strong>Eingebaute Migration</strong> – Es gibt einen Migrationspfad von bestehenden <code>.strings</code>- und <code>.stringsdict</code>-Dateien. Rechtsklicke auf deine vorhandenen Lokalisierungsdateien und Xcode bietet an, sie ins neue Format zu konvertieren.</p><h2 id="praktische-auswirkungen">Praktische Auswirkungen</h2><p>Für Projekte mit auch nur einer Handvoll unterstützter Sprachen ist das eine erhebliche Verbesserung der Lebensqualität. Der visuelle Editor allein eliminiert eine ganze Klasse von Formatierungsfehlern. Kombiniert mit der automatischen Extraktion bedeutet es weniger vergessene Strings und ein klareres Bild deines Lokalisierungsstatus im gesamten Projekt.</p><p>Wenn du ein neues Projekt mit Xcode 15 startest, sind String Catalogs der Standard. Für bestehende Projekte ist die Migration unkompliziert und lohnt sich auf jeden Fall.</p>]]></content:encoded>
</item>
<item>
<title>Xcode 15: Parameter auf mehrere Zeilen aufteilen</title>
<link>https://fline.dev/de/snippets/xcode-15-format-parameters-multiple-lines/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/xcode-15-format-parameters-multiple-lines/</guid>
<pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Xcode 15 fügt eine eingebaute Aktion hinzu, um lange Funktionsparameterlisten von einer einzelnen Zeile auf mehrere Zeilen umzuformatieren.]]></description>
<content:encoded><![CDATA[<h2 id="das-formatierungsproblem">Das Formatierungsproblem</h2><p>Lange Funktionsaufrufe und -deklarationen mit vielen Parametern sind eines der häufigsten Lesbarkeitsprobleme in Swift-Code. Man endet mit Zeilen, die weit über jede vernünftige Spaltengrenze hinausgehen:</p><pre><code class="language-swift">func configureView(title: String, subtitle: String, icon: Image, backgroundColor: Color, isEnabled: Bool, action: @escaping () -&gt; Void) {</code></pre><p>Das manuell in mehrere Zeilen umzubrechen ist mühsam. Du musst den Cursor positionieren, Zeilenumbrüche einfügen, jeden Parameter einrücken und sicherstellen, dass die schließende Klammer korrekt ausgerichtet ist.</p><h2 id="die-neue-aktion-in-xcode-15">Die neue Aktion in Xcode 15</h2><p>Xcode 15 führt eine „Format to Multiple Lines”-Aktion ein, die das automatisch erledigt. Setze deinen Cursor auf einen Funktionsaufruf oder eine Deklaration mit mehreren Parametern, und Xcode bietet an, es umzuformatieren:</p><p><img src="/assets/images/snippets/xcode-15-format-parameters-multiple-lines/format-to-multiple-lines.webp" alt="The Format to Multiple Lines option in Xcode 15" loading="lazy" /></p><p>Das Ergebnis ist sauber formatiert mit einem Parameter pro Zeile:</p><pre><code class="language-swift">func configureView(
   title: String,
   subtitle: String,
   icon: Image,
   backgroundColor: Color,
   isEnabled: Bool,
   action: @escaping () -&gt; Void
) {</code></pre><p>Du findest diese Aktion per Rechtsklick auf die Funktionssignatur unter <strong>Refactor</strong> oder über das <strong>Editor</strong>-Menü. Es funktioniert sowohl bei Funktionsdeklarationen als auch bei Aufrufstellen.</p><h2 id="wann-man-es-einsetzt">Wann man es einsetzt</h2><p>Das ist am nützlichsten direkt nach dem Schreiben einer neuen Funktion oder dem Hinzufügen von Parametern zu einer bestehenden. Anstatt beim Schreiben manuell zu formatieren, kannst du alles in eine Zeile schreiben und dann den Formatierer in einer einzigen Aktion anwenden. Es hilft auch beim Code-Review, wenn jemand anderes lange einzeilige Signaturen hinterlassen hat – markieren und umformatieren ohne manuelles Editieren.</p><p>Die umgekehrte Operation (mehrere Zeilen zurück in eine zusammenfalten) ist derzeit nicht verfügbar, aber diese Richtung wird seltener benötigt.</p>]]></content:encoded>
</item>
<item>
<title>Ladezustände in SwiftUI previews ohne Änderungen am Produktionscode</title>
<link>https://fline.dev/de/snippets/preview-loading-states-swiftui/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/preview-loading-states-swiftui/</guid>
<pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Ein Preview-only Helper, der Netzwerkverzögerungen simuliert, damit du Ladezustände in SwiftUI Previews sehen kannst.]]></description>
<content:encoded><![CDATA[<h2 id="die-herausforderung">Die Herausforderung</h2><p>Beim Erstellen von Views, die von asynchronen Daten abhängen, hast du typischerweise einen Ladezustand, der einen Spinner oder Platzhalter anzeigt. In der Produktion erscheint dieser Zustand kurz, während Daten aus dem Netzwerk oder der Datenbank geladen werden. Aber in SwiftUI Previews sind deine Mock-Daten sofort verfügbar, sodass der Ladezustand zu schnell vorbeihuscht, um ihn zu begutachten – oder gar nicht erst erscheint.</p><h2 id="ein-rein-auf-previews-beschränkter-delay-helper">Ein rein auf Previews beschränkter Delay-Helper</h2><p>Die Lösung ist ein kleiner Helper, der eine künstliche Verzögerung einführt, aber nur im Preview- oder Debug-Kontext. Hier ist das Muster:</p><pre><code class="language-swift">struct DelayedStatePreview&lt;Content: View&gt;: View {
   @State private var isLoaded = false
   let delay: Duration
   let content: (Bool) -&gt; Content

   init(
      delay: Duration = .seconds(2),
      @ViewBuilder content: @escaping (Bool) -&gt; Content
   ) {
      self.delay = delay
      self.content = content
   }

   var body: some View {
      content(isLoaded)
         .task {
            try? await Task.sleep(for: delay)
            isLoaded = true
         }
   }
}</code></pre><p>Du verwendest es in einem Preview so:</p><pre><code class="language-swift">#Preview {
   DelayedStatePreview { isLoaded in
      if isLoaded {
         ArticleListView(articles: mockArticles)
      } else {
         LoadingView()
      }
   }
}</code></pre><p><img src="/assets/images/snippets/preview-loading-states-swiftui/code-example.webp" alt="Code example showing the preview helper in context" loading="lazy" /></p><h2 id="warum-das-wichtig-ist">Warum das wichtig ist</h2><p>Der entscheidende Vorteil ist, dass dein Produktionscode sauber bleibt. Du fügst keine künstlichen Verzögerungen oder Debug-Flags zu deinen eigentlichen Views hinzu. Der Helper existiert rein auf der Preview-Ebene und gibt dir die Möglichkeit, visuell zu überprüfen, ob deine Ladezustände korrekt aussehen, ob Übergänge flüssig animieren und ob das Layout nicht springt, wenn Daten ankommen.</p><p>Das ist besonders nützlich für Views mit Skeleton-Loadern oder Shimmer-Effekten, bei denen die visuelle Qualität des Ladezustands Teil der User Experience ist.</p>]]></content:encoded>
</item>
<item>
<title>Xcode-Starts durch Deaktivieren des Debug-Executables beschleunigen</title>
<link>https://fline.dev/de/snippets/speed-up-xcode-disable-debug-executable/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/speed-up-xcode-disable-debug-executable/</guid>
<pubDate>Wed, 10 May 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Eine versteckte Xcode-Scheme-Einstellung, die die App-Startzeiten während der Entwicklung deutlich verkürzen kann.]]></description>
<content:encoded><![CDATA[<h2 id="das-problem-mit-dem-leeren-bildschirm">Das Problem mit dem leeren Bildschirm</h2><p>Wenn du jemals eine Verzögerung bemerkt hast – manchmal mehrere Sekunden – zwischen dem Drücken von Run in Xcode und dem tatsächlichen Erscheinen deiner App, ist der Übeltäter oft der LLDB-Debugger, der sich an deinen Prozess anhängt. Während dieser Zeit zeigt der Simulator einen leeren Bildschirm, während der Debugger initialisiert wird.</p><p><img src="/assets/images/snippets/speed-up-xcode-disable-debug-executable/comparison.webp" alt="Comparison of launch times with and without debug executable enabled" loading="lazy" /></p><h2 id="wo-die-einstellung-zu-finden-ist">Wo die Einstellung zu finden ist</h2><p>Die Einstellung befindet sich in deiner Scheme-Konfiguration:</p><ol><li><p>Gehe zu <strong>Product &gt; Scheme &gt; Edit Scheme</strong> (oder drücke Cmd+Shift+&lt;)</p></li><li><p>Wähle links die <strong>Run</strong>-Aktion aus</p></li><li><p>Wechsle zum <strong>Info</strong>-Tab</p></li><li><p>Deaktiviere <strong>Debug executable</strong></p></li></ol><p><img src="/assets/images/snippets/speed-up-xcode-disable-debug-executable/setting-before.webp" alt="The setting before the change" loading="lazy" /></p><p><img src="/assets/images/snippets/speed-up-xcode-disable-debug-executable/setting-after.webp" alt="The setting after unchecking Debug executable" loading="lazy" /></p><h2 id="was-das-bewirkt">Was das bewirkt</h2><p>Wenn „Debug executable” aktiviert ist (der Standard), hängt Xcode den LLDB-Debugger beim Start an deinen App-Prozess an. Das ist es, was Breakpoints, den Debug Memory Graph, den View Hierarchy Debugger und <code>po</code>-Befehle in der Konsole ermöglicht.</p><p>Das Deaktivieren überspringt das Anhängen des Debuggers komplett. Deine App startet merklich schneller – meiner Erfahrung nach kann der Unterschied bei größeren Projekten 2 bis 5 Sekunden betragen. Konsolenausgaben über <code>print()</code> und <code>os_log</code> funktionieren weiterhin normal, sodass du Logging fürs Debugging weiter nutzen kannst.</p><h2 id="der-kompromiss">Der Kompromiss</h2><p>Ohne angehängten Debugger verlierst du:</p><ul><li><p>Breakpoints (sie werden nicht ausgelöst)</p></li><li><p><code>po</code>- und <code>expression</code>-Befehle in der Konsole</p></li><li><p>Memory Graph und View Hierarchy Debugging-Tools</p></li></ul><p>Das macht die Einstellung ideal für UI-Iterationsarbeit, wenn du visuelle Anpassungen machst und häufig neu startest. Wenn du einen bestimmten Bug mit Breakpoints untersuchen musst, aktiviere das Kontrollkästchen einfach vorübergehend wieder. Ich lasse es die meiste Zeit deaktiviert und schalte es nur ein, wenn ich Code Schritt für Schritt durchgehen muss.</p>]]></content:encoded>
</item>
<item>
<title>Xcode Code Snippets für Entwicklerwarnungen</title>
<link>https://fline.dev/de/snippets/xcode-snippets-developer-warnings/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/xcode-snippets-developer-warnings/</guid>
<pubDate>Sun, 07 May 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Xcode Code Snippets mit #warning nutzen, um umsetzbare Erinnerungen in deiner Codebasis zu hinterlassen.]]></description>
<content:encoded><![CDATA[<h2 id="warum-warning-in-der-entwicklung-wichtig-ist">Warum #warning in der Entwicklung wichtig ist</h2><p>Swifts <code>#warning</code>-Direktive erzeugt eine Compiler-Warnung mit einer benutzerdefinierten Nachricht. Anders als Kommentare tauchen diese im Issue Navigator und in der Build-Ausgabe auf, sodass man sie unmöglich übersehen kann. Ich verwende sie als harte Erinnerungen für Dinge, die vor dem Release unbedingt erledigt werden müssen.</p><h2 id="zwei-snippets-die-ich-täglich-nutze">Zwei Snippets, die ich täglich nutze</h2><p>Ich habe zwei Xcode Code Snippets für diesen Zweck eingerichtet.</p><p><strong>“nyi” – Not Yet Implemented:</strong></p><pre><code class="language-swift">#warning(&quot;Not yet implemented!&quot;)</code></pre><p>Ich tippe <code>nyi</code> und drücke Enter, wann immer ich eine Funktion auslagere oder beim Prototyping einen Codepfad überspringe. Es kompiliert problemlos, aber die Warnung stellt sicher, dass ich zurückkomme, um die Arbeit zu beenden.</p><p><strong>“dw” – Developer Warning:</strong></p><pre><code class="language-swift">#warning(&quot;&lt;#message#&gt;&quot;)</code></pre><p>Dieses Snippet verwendet ein Platzhalter-Token, sodass nach dem Tippen von <code>dw</code> und Drücken von Enter der Cursor in der Nachricht landet und ich eine individuelle Notiz eingeben kann. Ich verwende das für Dinge wie <code>#warning(&quot;Handle error case for offline mode&quot;)</code> oder <code>#warning(&quot;Remove before release&quot;)</code>.</p><h2 id="so-erstellt-man-xcode-snippets">So erstellt man Xcode Snippets</h2><p>Das Einrichten dauert jeweils etwa 30 Sekunden:</p><ol><li><p>Tippe den gewünschten Code als Snippet in eine beliebige Swift-Datei</p></li><li><p>Markiere den Code</p></li><li><p>Rechtsklick und <strong>Create Code Snippet</strong> wählen</p></li><li><p>Gib ihm einen Titel (z.B. „Developer Warning”)</p></li><li><p>Setze die <strong>Completion</strong>-Abkürzung (z.B. <code>dw</code>)</p></li><li><p>Setze <strong>Availability</strong> auf „All” oder „Swift”</p></li><li><p>Klicke auf Done</p></li></ol><p>Von da an bietet das Tippen der Abkürzung in jeder Swift-Datei das Snippet über die Autovervollständigung an.</p><p>Der entscheidende Vorteil gegenüber reinen Kommentaren ist die Sichtbarkeit. Ein <code>// TODO:</code>-Kommentar lässt sich leicht ignorieren und ist schwer konsistent zu finden. Ein <code>#warning</code> zwingt den Compiler, es bei jedem einzelnen Build anzuzeigen, und hält deine unfertige Arbeit im Vordergrund, bis du sie erledigst.</p>]]></content:encoded>
</item>
<item>
<title>Schneller Zugriff auf Swift-Evolution-Proposal-Zusammenfassungen auf GitHub</title>
<link>https://fline.dev/de/snippets/swift-evolution-proposal-summaries-github/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/swift-evolution-proposal-summaries-github/</guid>
<pubDate>Tue, 02 May 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Ein einfacher URL-Trick, um zusammengefasste Versionen von Swift Evolution Proposals auf GitHub zu lesen.]]></description>
<content:encoded><![CDATA[<h2 id="das-problem-mit-proposal-dokumenten">Das Problem mit Proposal-Dokumenten</h2><p>Swift Evolution Proposals sind von Natur aus ausführlich. Sie behandeln Motivation, detailliertes Design, betrachtete Alternativen, ABI-Auswirkungen und mehr. Diese Gründlichkeit ist für den Review-Prozess unverzichtbar, aber wenn du nur verstehen willst, was ein Proposal macht und warum, kann das Durchlesen von tausenden Wörtern ganz schön viel sein.</p><h2 id="der-url-trick">Der URL-Trick</h2><p>Es gibt eine einfache Möglichkeit, eine zusammengefasste Version jedes Swift Evolution Proposals auf GitHub zu bekommen. Wenn du ein Proposal unter einer URL wie dieser betrachtest:</p><pre><code>https://github.com/apple/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md</code></pre><p>Ersetze <code>apple</code> durch <code>FlineDev</code>:</p><pre><code>https://github.com/FlineDev/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md</code></pre><p>Das führt dich zu einem Fork des swift-evolution Repository, in dem Proposals um KI-generierte Zusammenfassungen am Anfang ergänzt wurden. Jede Zusammenfassung destilliert die wichtigsten Punkte – was das Proposal einführt, warum es wichtig ist und die grundlegende Syntax – in wenige Absätze.</p><h2 id="wann-das-hilfreich-ist">Wann das hilfreich ist</h2><p>Das ist besonders nützlich, wenn du ein Proposal in Release Notes oder in sozialen Medien erwähnt siehst und schnell den Kern verstehen willst. Anstatt 15 Minuten mit dem vollständigen Proposal zu verbringen, bekommst du die wesentlichen Informationen in ein paar Minuten.</p><p>Die Zusammenfassungen decken die meisten kürzlich akzeptierten Proposals ab. Für ältere Proposals, die vor dem Fork erstellt wurden, siehst du weiterhin den Originaltext. Aber für alles aus den letzten Jahren der Swift Evolution ist die zusammengefasste Version ein echter Zeitsparer.</p><p>Ich habe diesen Fork erstellt, weil ich mich immer wieder dabei ertappt habe, Proposals nur nach der Kernidee zu durchsuchen, und dachte, dass andere Entwickler von der gleichen Abkürzung profitieren könnten.</p>]]></content:encoded>
</item>
<item>
<title>Pulsating Button Animation in SwiftUI</title>
<link>https://fline.dev/de/snippets/pulsating-button-animation-swiftui/</link>
<guid isPermaLink="true">https://fline.dev/de/snippets/pulsating-button-animation-swiftui/</guid>
<pubDate>Fri, 07 Apr 2023 00:00:00 +0000</pubDate>
<description><![CDATA[Wie man einen pulsierenden Button-Effekt in SwiftUI erstellt, um Nutzer beim Onboarding zu leiten.]]></description>
<content:encoded><![CDATA[<h2 id="guiding-users-with-a-pulsating-button">Guiding Users with a Pulsating Button</h2><p>Beim Erstellen eines Onboarding-Flows besteht eine Herausforderung darin, die Aufmerksamkeit des Nutzers auf die nächste Aktion zu lenken. Eine dezente pulsierende Animation auf Buttons zieht den Blick an, ohne aufdringlich zu sein. Ich habe das in SwiftUI mit einer Kombination aus <code>scaleEffect</code>- und <code>opacity</code>-Modifiern umgesetzt, die an eine sich wiederholende Animation gekoppelt sind.</p><p>Hier ist der grundlegende Ansatz:</p><pre><code class="language-swift">struct PulsatingButtonStyle: ButtonStyle {
   @State private var isPulsating = false

   func makeBody(configuration: Configuration) -&gt; some View {
      configuration.label
         .scaleEffect(isPulsating ? 1.06 : 1.0)
         .opacity(isPulsating ? 0.8 : 1.0)
         .animation(
            .easeInOut(duration: 0.8)
               .repeatForever(autoreverses: true),
            value: isPulsating
         )
         .onAppear {
            isPulsating = true
         }
   }
}</code></pre><p>Der Trick besteht darin, zwei Animationen – Skalierung und Transparenz – zu kombinieren, die synchron laufen. Der <code>repeatForever(autoreverses: true)</code>-Modifier lässt die Animation kontinuierlich hin und her schwingen. Durch das Umschalten von <code>isPulsating</code> beim Erscheinen startet die Animation sofort, wenn die View angezeigt wird.</p><p><video src="/assets/images/snippets/pulsating-button-animation-swiftui/demo.mp4" controls muted playsinline></video></p><p>Der Skalierungsfaktor von 1.06 ist bewusst dezent gewählt. Ein deutlich höherer Wert (wie 1.2) lässt die Animation aggressiv und ablenkend wirken. Die leichte Transparenzänderung verleiht dem Puls Tiefe, ohne den Button schwer lesbar zu machen.</p><p>Dieses Muster eignet sich gut für Onboarding-Screens, auf denen du einen „Weiter”- oder „Los geht’s”-Button hervorheben möchtest. Sobald der Nutzer das Onboarding hinter sich hat, wird die Animation nicht mehr angezeigt, sodass sie mit der Zeit nicht nervt.</p><p>Du kannst sie auf jeden Button mit <code>.buttonStyle(PulsatingButtonStyle())</code> anwenden und hältst die Animationslogik sauber von deinem Button-Inhalt getrennt.</p>]]></content:encoded>
</item>
</channel>
</rss>