Eine Swift-6.3-Umstellung erzeugt plötzlich zahlreiche Nebenläufigkeitsdiagnosen, Abhängigkeiten brechen den Build und mehrere Targets verhalten sich unterschiedlich.
Die schnellste Lösung: Lassen Sie den Swift-6.3-Compiler zunächst mit dem bisherigen Swift language mode laufen, sichern Sie die Build- und Testbasis und migrieren Sie danach einzelne Targets — bei Bedarf parallel mit alter Sprachversion und neuer Toolchain.
Stand: 24.08.2026. Die Einordnung von Swift 6.3 und die empfohlenen Migrationsschritte sind anhand der offiziellen Swift-6.3-Veröffentlichung und der Swift-Migrationsdokumentation geprüft.
Für wen dieser Runbook gedacht ist
Diese Anleitung richtet sich an iOS- und macOS-Entwickler, bei denen Swift Concurrency nach dem Upgrade deutlich mehr Diagnosen meldet. Sie ist außerdem für technische Verantwortliche mit Multi-Target-Projekten, gemischtem Swift-, Objective-C- und C-Code sowie älteren Abhängigkeiten gedacht.
Auch Buildingenieure profitieren davon, wenn sie Swift 6.3 in CI/CD prüfen müssen, ohne den derzeit veröffentlichbaren Build zu gefährden.
Die eigentliche Ursache zuerst trennen
Der häufigste Denkfehler lautet: „Der Compiler ist auf Swift 6.3 aktualisiert, also muss das gesamte Projekt sofort im Swift-6-Modus kompiliert werden.“ Das sind jedoch zwei getrennte Einstellungen.
Die Toolchain bestimmt, welcher Compiler, welche Standardbibliothek und welche Diagnosefunktionen verwendet werden. Der Swift language mode legt dagegen fest, nach welchen Sprachregeln ein einzelnes Target geprüft wird. Ein Projekt kann deshalb bereits mit Swift 6.3 gebaut werden, während einzelne Targets noch im Swift-5-Modus bleiben.
Die Swift-Kompatibilitätsdokumentation beschreibt diese Trennung. Für die Migration bedeutet das:
- Ein Compiler-Upgrade ist zunächst eine Infrastrukturänderung.
- Der Wechsel des Swift language mode ist eine Quellcode- und Verhaltensänderung.
- Die Umstellung aller Targets auf einmal vergrößert die Fehlerfläche unnötig.
- Ein Fehler in einer alten Bibliothek beweist nicht, dass der eigene Nebenläufigkeitscode falsch ist.
- Eine verschwundene Warnung ist kein ausreichender Nachweis für Thread-Sicherheit.
Erfassen Sie vor der ersten Änderung pro Target mindestens den aktuellen Sprachmodus, die verwendete Toolchain, die Abhängigkeitsversionen, die Warnungsarten, den Status der Unit- und Integrationstests sowie die erzeugten Artefakte. Halten Sie außerdem fest, ob Signierung, Archivierung und Installation auf realen Testgeräten funktionieren. Ohne diese Basis können Sie später nicht sicher unterscheiden, ob ein Problem aus dem Compiler, aus einer Abhängigkeit oder aus einer eigenen Codeänderung stammt.
Compiler und Sprachmodus im direkten Vergleich
| Einstellung | Was sich ändert | Typisches Risiko | Sinnvoller erster Schritt |
|---|---|---|---|
| Swift-6.3-Compiler | Toolchain und Diagnoseverhalten | Neue Warnungen oder Unterschiede in Abhängigkeiten | Mit unverändertem Sprachmodus bauen |
| Swift language mode 5 | Bestehende Sprachregeln bleiben aktiv | Sicherheitsprobleme werden eventuell noch nicht vollständig diagnostiziert | Als stabile Vergleichsbasis behalten |
| Swift language mode 6 | Strengere Prüfung der Nebenläufigkeit | Viele Fehler an gemeinsamem Zustand und asynchronen Grenzen | Zuerst in einem kleinen, gut getesteten Target aktivieren |
| Gemischte Modi im Projekt | Targets werden unabhängig migriert | Unterschiedliche Erwartungen an Module und Schnittstellen | Modulgrenzen und Importpfade dokumentieren |
Was tun Sie, wenn nach dem Upgrade zu viele Nebenläufigkeitsfehler erscheinen?
Schalten Sie nicht reflexartig Warnungen ab und ergänzen Sie nicht pauschal @unchecked Sendable. Prüfen Sie zuerst, ob das betroffene Target tatsächlich in den Swift-6-Modus gewechselt ist. Danach gruppieren Sie die Diagnosen nach gemeinsamem veränderlichem Zustand, Actor-Isolation, Sendable-Grenzen und asynchronen Übergängen. Eine kleine Zahl wiederkehrender Ursachen ist meist produktiver als eine lange Liste einzelner Fehlermeldungen.
Erste Diagnose: eine reproduzierbare Ausgangslage schaffen
Bevor Sie Quellcode umstrukturieren, legen Sie einen separaten Migrationszweig an. Führen Sie dort denselben Build wie im stabilen Zweig aus und speichern Sie:
- den vollständigen Compileraufruf oder die relevanten Build-Einstellungen;
- die Abhängigkeitsauflösung und alle Lock-Dateien;
- die Warnungs- und Fehlerausgabe je Target;
- die Ergebnisse der vorhandenen Unit-, Integrations- und Nebenläufigkeitstests;
- den Status von Archiv, Signierung und Installationsprüfung.
Nutzen Sie für jede spätere Änderung möglichst einen kleinen Commit. Wenn ein Fehler zunimmt, können Sie so auf den letzten reproduzierbaren Zustand zurückgehen, anstatt eine große, untrennbare Migrationsänderung rückgängig zu machen.
Die offizielle Anleitung zur inkrementellen Nebenläufigkeitsmigration empfiehlt genau diesen schrittweisen Ansatz: Aktivieren Sie die strengere Prüfung dort, wo Sie die Auswirkungen kontrollieren können, und erweitern Sie den Bereich erst nach erfolgreicher Validierung.
Woran erkennen Sie, ob der Compiler oder der Swift language mode die Meldung auslöst?
Bauen Sie dasselbe Target mit identischem Quellcode einmal in der bisherigen Sprachversion und einmal im Zielmodus. Bleibt der Fehler im alten Modus aus, handelt es sich wahrscheinlich um eine neu aktivierte Sprachprüfung. Tritt er in beiden Modi auf, müssen Sie zusätzlich Typdefinitionen, Abhängigkeiten, Compilerargumente oder eine bereits bestehende Warnung untersuchen. Vergleichen Sie nicht nur die IDE-Ausgabe, sondern die vollständigen CI-Protokolle.
Zweiter Schritt: Nebenläufigkeit nach Ursache statt nach Fehlermeldung sortieren
Swift Concurrency prüft nicht einfach, ob eine Funktion async heißt. Problematisch sind vor allem Datenflüsse, bei denen veränderlicher Zustand eine Isolation überschreitet oder ein Wert an eine gleichzeitig ausgeführte Aufgabe übergeben wird.
Teilen Sie die Diagnosen in vier Gruppen:
Gemeinsam veränderlicher Zustand
Suchen Sie nach globalen Variablen, statischen veränderlichen Eigenschaften, gemeinsam genutzten Caches und Klassen, die von mehreren Aufgaben verändert werden. Entscheidend ist nicht, ob bisher ein Fehler beobachtet wurde, sondern ob mehrere Ausführungspfade denselben Zustand ohne klare Synchronisation erreichen können.
Mögliche Reparaturen sind ein Actor, eine unveränderliche Wertstruktur oder eine klar begrenzte Synchronisationsschicht. Verschieben Sie den Zustand nicht lediglich in eine andere Klasse. Wenn die Zugriffskette unverändert bleibt, wurde das Problem nur umbenannt.
Actor-Isolation
Ein Actor schützt seinen isolierten Zustand, erzeugt aber eine klare Zugriffsgrenze. Aufrufe aus einem anderen Ausführungskontext müssen diese Grenze berücksichtigen. Die Dokumentation zur Actor-Isolation erklärt das zugrunde liegende Modell.
Prüfen Sie bei jeder Diagnose:
- Wo wird der Zustand gelesen oder verändert?
- Muss die gesamte Methode isoliert sein oder nur ein Teil?
- Wird ein nicht isolierter Rückruf in eine isolierte Instanz hinein verlängert?
- Entsteht durch die Reparatur eine unnötige Serialisierung?
Eine globale Annotation kann den Compiler ruhigstellen, aber sie kann auch die tatsächliche Ausführungsstruktur verschleiern. Wählen Sie deshalb die kleinste Isolationseinheit, die den Besitz und den Zugriff eindeutig macht.
Sendable-Grenzen
Werte, die zwischen konkurrierenden Aufgaben übertragen werden, müssen sicher gemeinsam verwendet werden können. Bei Werttypen ist die Analyse häufig überschaubarer; bei Referenztypen müssen Sie mutierbaren internen Zustand und Lebenszyklus genauer prüfen.
@unchecked Sendable ist keine Reparatur. Dieses Attribut verschiebt die Verantwortung auf Sie. Verwenden Sie es nur, wenn eine unabhängige Prüfung nachweist, dass Synchronisation oder unveränderliche Nutzung tatsächlich gewährleistet ist. Dokumentieren Sie dabei die Invariante und einen Test, der sie absichert.
Asynchrone Grenzen
Delegates, Completion-Handler, Benachrichtigungen, Timer, Datenbankzugriffe und C-Callbacks sind typische Übergänge, an denen Isolation verloren geht. Zeichnen Sie für jede betroffene Funktion den Weg vom Aufrufer bis zum Callback auf. Oft liegt die eigentliche Ursache nicht in der markierten Zeile, sondern in einem älteren API-Design, das einen beliebigen Ausführungskontext voraussetzt.
Die WWDC-Einführung zu Swift Concurrency ist für diese Zuordnung hilfreich, weil sie Isolation, Tasks und strukturierte Nebenläufigkeit im Zusammenhang erklärt.
Dritter Schritt: Alte Abhängigkeiten an einer Grenze isolieren
Wie behandeln Sie eine Drittanbieterabhängigkeit, die Swift 6.3 noch nicht unterstützt?
Prüfen Sie zuerst das offizielle Repository oder die offizielle Versionsdokumentation des jeweiligen Projekts. Suchen Sie nach einer kompatiblen Version, einer dokumentierten Quellcodekorrektur oder einer Ersatzimplementierung. Ändern Sie die Abhängigkeit nicht direkt im gesamten Quellcode, solange ihre Kompatibilität nicht geklärt ist.
Legen Sie stattdessen ein Boundary-Modul oder einen Adapter an. Dieses Modul darf die alte API kennen; der übrige Code arbeitet mit eigenen, möglichst einfachen Typen. So bleibt die spätere Aktualisierung auf eine kompatible Version lokal.
| Abhängigkeitslage | Vorgehen | Was Sie vermeiden sollten | Freigabekriterium |
|---|---|---|---|
| Kompatible Quellversion verfügbar | Version aktualisieren und isoliert testen | Gleichzeitig mehrere Kernmodule umbauen | Build, Tests und Artefaktprüfung erfolgreich |
| Quellcode vorhanden, aber Diagnosen an der API-Grenze | Adapter oder Boundary-Modul anlegen | Fremdtypen unkontrolliert durch alle Targets reichen | Nur die Grenze benötigt Sonderbehandlung |
| Binärmodul ohne passende Variante | Herstellerfreigabe abwarten oder Ersatz prüfen | Binärdatei blind neu signieren oder intern patchen | Import, Link, Laufzeit und Signierung geprüft |
| Keine Wartung und keine Alternative | Migration des betroffenen Funktionsbereichs planen | Unsichere Attribute im gesamten Projekt verteilen | Rückfallpfad und Eigentümer des Moduls festgelegt |
Bei Binärmodulen müssen Sie zusätzlich prüfen, ob Modulformat, Zielplattform, Architektur, Signatur und verwendete Swift-Umgebung zusammenpassen. Ein erfolgreicher lokaler Import genügt nicht, wenn das Modul im Archiv- oder CI-Schritt anders behandelt wird.
Wenn Sie Mac-Buildumgebungen für diese Prüfung trennen, dokumentieren Sie Toolchain, Zertifikatszugriff und Abhängigkeitscache je Knoten. Für den späteren Distributionsschritt ist die offizielle Dokumentation zur Erstellung signierter Mac-Codes maßgeblich. Die Signierung gehört zur Abnahme, nicht nur zur letzten Veröffentlichung.
Vierter Schritt: Targets und gemischte Sprachgrenzen in einer Reihenfolge migrieren
Wie migrieren Sie ein großes Projekt Target für Target?
Beginnen Sie mit einem Target, das wenige Abhängigkeiten, eine vollständige Testabdeckung und klar abgegrenzte Schnittstellen besitzt. Migrieren Sie nicht automatisch das wichtigste oder größte Modul zuerst. Das erste Target soll Erkenntnisse liefern, ohne die gesamte Veröffentlichung zu blockieren.
Eine robuste Reihenfolge sieht so aus:
- Dokumentieren Sie alle Targets, ihre Abhängigkeiten und ihre Testbefehle.
- Wählen Sie ein kleines Infrastruktur- oder Funktionsmodul mit reproduzierbarem Build.
- Aktivieren Sie dort den Swift-6-Modus im Migrationszweig.
- Reparieren Sie die vier Diagnosegruppen getrennt voneinander.
- Prüfen Sie abhängige Targets, ohne sie sofort ebenfalls umzustellen.
- Migrieren Sie danach Module mit klaren Schnittstellen und hoher Testabdeckung.
- Verschieben Sie zentrale Geschäftslogik erst dann, wenn die Randmodule stabil sind.
- Entfernen Sie alte Kompatibilitätsmaßnahmen nur nach einer erfolgreichen Gesamtprüfung.
In gemischten Projekten ist die Sprachgrenze selbst ein Risiko. Swift kann über Objective-C sichtbare APIs nutzen; C-Schnittstellen können Zeiger, Rückrufkontexte oder globale Zustände enthalten, deren Nebenläufigkeit der Swift-Typchecker nicht vollständig ausdrückt. Prüfen Sie daher nicht nur, ob ein Header kompiliert. Testen Sie Eigentum, Lebensdauer, Callback-Reihenfolge, Fehlerpfade und die Nutzung aus mehreren Aufgaben.
Ein Objective-C-Delegate, der früher implizit auf dem Hauptthread lief, kann nach einer asynchronen Swift-Anbindung eine andere Ausführungserwartung bekommen. Halten Sie diese Erwartung an der Schnittstelle fest und testen Sie sie. Bei C-APIs müssen Sie insbesondere prüfen, ob ein übergebener Zeiger während der gesamten asynchronen Operation gültig bleibt.
Welche Nachteile hat die stufenweise Migration?
Sie müssen vorübergehend mehrere Sprachmodi, zusätzliche Adapter und mehr CI-Konfiguration verwalten. Das erhöht den Dokumentationsaufwand und kann Diagnoseunterschiede zwischen Targets sichtbar machen. Der Vorteil ist jedoch, dass jede Änderung einem Modul zugeordnet werden kann und ein fehlgeschlagenes Target nicht automatisch den stabilen Veröffentlichungszweig blockiert.
Fünfter Schritt: Zwei Toolchains in CI/CD gegeneinander prüfen
Eine Migrationspipeline darf den produktiven Build nicht ersetzen, bevor sie dieselben Ausgaben und Tests zuverlässig reproduziert. Lassen Sie deshalb zwei Pfade parallel laufen:
- Der stabile Pfad verwendet den bisherigen Sprachmodus und erzeugt das derzeit freigegebene Artefakt.
- Der Migrationspfad verwendet den Swift-6.3-Compiler und die bereits umgestellten Targets.
- Beide Pfade verwenden eine festgelegte Abhängigkeitsauflösung.
- Beide prüfen Kompilierung, Tests, Archivierung, Signierung und das Verhalten des erzeugten Artefakts.
Vergleichen Sie nicht nur die Exit-Codes. Prüfen Sie, ob sich Warnungen, Testdauer, Installierbarkeit, Laufzeitverhalten und Signaturstatus verändert haben. Ein Build, der kompiliert, aber wegen eines falschen Zertifikats oder einer abweichenden Bundle-Konfiguration nicht installiert werden kann, ist kein erfolgreicher Migrationsnachweis.
Bewahren Sie die Toolchain-Auswahl als reproduzierbare CI-Konfiguration auf. Verlassen Sie sich nicht auf die lokal installierte Standardversion eines einzelnen Rechners. Gerade bei einem temporären Mac-Buildknoten müssen Sie festhalten, welche Xcode- beziehungsweise Swift-Umgebung, welche Zertifikate und welche Cache-Inhalte verwendet werden.
Für die operative Trennung können Sie eine isolierte Mac-Buildumgebung als unabhängigen Prüfpfad konfigurieren. Entscheidend ist nicht die bloße Verfügbarkeit eines zusätzlichen Rechners, sondern die reproduzierbare Trennung vom einzigen veröffentlichenden Knoten. Hinweise zu Zugriffsrechten und Betriebsabläufen finden Sie im Macstripe-Hilfezentrum; geben Sie dort keine unnötigen privaten Schlüssel oder personenbezogenen Projektdaten weiter.
Rückkehrplan: Migration abbrechen, ohne den Veröffentlichungszweig zu beschädigen
Wie können Sie eine fehlgeschlagene Swift-6.3-Migration zurückrollen?
Behandeln Sie die Migration als separaten, jederzeit verwerfbaren Pfad. Der stabile Zweig behält seine bekannte Toolchain, seine Lock-Datei und seine Signierungsabläufe. Änderungen an Abhängigkeiten und Sprachmodus werden einzeln versioniert. So können Sie entweder das letzte Target zurücksetzen oder den gesamten Migrationszweig schließen, ohne Produktionscode nachträglich reparieren zu müssen.
Ein belastbarer Rückkehrplan umfasst:
- einen unveränderten stabilen Build als Referenz;
- einen dokumentierten Commit pro Target und pro Abhängigkeitsänderung;
- gesicherte Test- und Archivartefakte beider Pfade;
- getrennte CI-Knoten oder klar getrennte Build-Konfigurationen;
- eine Entscheidung, wer den Rollback auslöst;
- einen Test, der die Rückkehr zum veröffentlichten Artefakt tatsächlich ausführt.
Ein Rollback ist erst verifiziert, wenn der alte Pfad erneut kompiliert, die Tests durchläuft, das Artefakt signiert wird und die vorgesehene Installation funktioniert. Das reine Zurücksetzen eines Branches sagt nichts über Caches, Abhängigkeitsauflösung oder Zertifikatszustände aus.
Abnahme: Wann ist die Umstellung wirklich abgeschlossen?
Setzen Sie nicht „keine sichtbaren Fehlermeldungen“ als einziges Ziel. Eine Migration ist erst abgeschlossen, wenn die Zielumgebungen und die relevanten Ausführungspfade geprüft wurden.
Verwenden Sie diese direkt abarbeitbare Liste:
- [ ] Für jedes Target sind Compiler-Version und Swift language mode dokumentiert.
- [ ] Die ursprüngliche Build-, Test-, Archiv- und Signierungsbasis ist reproduzierbar.
- [ ] Diagnosen sind nach gemeinsamem Zustand, Actor-Isolation, Sendable und asynchronen Grenzen bewertet.
- [ ] Unsichere Attribute sind einzeln begründet und durch Tests oder Invarianten abgesichert.
- [ ] Jede alte Abhängigkeit hat eine bestätigte Version, eine isolierte Adaptergrenze oder einen dokumentierten Ersatzplan.
- [ ] Swift-, Objective-C- und C-Schnittstellen sind mit Callback-, Eigentums- und Lebensdauertests geprüft.
- [ ] Der stabile und der migrierte CI/CD-Pfad laufen parallel und erzeugen vergleichbare Prüfberichte.
- [ ] Unit-, Integrations-, Nebenläufigkeits- und Installationstests bestehen auf allen Zielumgebungen.
- [ ] Archivierung und Signierung sind nach der Migration erneut geprüft.
- [ ] Der Rückfall auf den stabilen Pfad wurde nicht nur geplant, sondern erfolgreich durchgeführt.
- [ ] Erst danach werden alte Toolchain-Knoten und vorübergehende Kompatibilitätsmaßnahmen entfernt.
Die passende Arbeitsumgebung für die Migration auswählen
| Situation | Lokaler Mac | Separater Macstripe-Knoten | Öffentliche Cloud-Umgebung |
|---|---|---|---|
| Ein Entwickler prüft ein kleines Target | Schnell und direkt | Meist unnötiger zusätzlicher Ablauf | Häufig zu viel Einrichtungsaufwand |
| Mehrere Targets benötigen parallele Validierung | Ressourcen und Zertifikatszugriff können kollidieren | Klare Trennung von stabilem und migriertem Pfad | Abhängig von Verfügbarkeit, Netzwerk und Richtlinien |
| Signierung und interne Abhängigkeiten | Einfach, wenn der Rechner bereits freigegeben ist | Sinnvoll bei isolierter Build- und Zugriffskontrolle | Vorher genau auf Schlüsselverwaltung und Datenschutz prüfen |
| Kurzfristige Migrationsphase | Blockiert eventuell andere Builds | Für einen unabhängigen Prüfpfad geeignet | Kann durch Toolchain- und Cache-Unterschiede schwer reproduzierbar sein |
| Dauerhafte, schwere Buildlast | Kauf oder eigener Knoten oft sinnvoller | Mietmodell muss gegen konstante Nutzung gerechnet werden | Laufende Kosten und Plattformgrenzen prüfen |
Ein zusätzlicher Knoten löst keine fehlerhafte Migrationsstrategie. Er verhindert aber, dass ein einziges Arbeits- oder Veröffentlichungsgerät gleichzeitig als Experimentierfläche und als Produktionspfad dienen muss. Bei vertraulichen Quelltexten, Zertifikaten und personenbezogenen Testdaten sollten Sie vorab Zugriffsrechte, Aufbewahrung, Löschung und DSGVO-Anforderungen klären.
Wenn Sie zunächst die organisatorischen und technischen Rahmenbedingungen vergleichen möchten, lesen Sie die Anleitung zum Konfigurieren einer Bestellung. Für eine dauerhafte Hochlastumgebung mit stabiler Auslastung kann ein eigener Mac wirtschaftlicher und administrativ einfacher sein. Für eine zeitlich begrenzte Migration ist ein unabhängiger Knoten dagegen oft leichter zu rechtfertigen, weil Sie die Produktionsumgebung nicht umbauen müssen.
Fazit für Ihren Swift-6.3-Migrationsplan
Swift 6.3 selbst ist nicht automatisch die Ursache jeder neuen Diagnose. Der Compiler, der Swift language mode, die Abhängigkeiten und die vorhandenen Codegrenzen müssen getrennt bewertet werden. Beginnen Sie mit einer belastbaren Basis, migrieren Sie Targets einzeln und behandeln Sie Datenrennen vor kosmetischen Warnungsbereinigungen. Erst wenn Nebenläufigkeit, Abhängigkeiten, gemischte Schnittstellen, CI/CD und Signierung geprüft sind, sollte der alte Pfad entfallen.
Wenn Ihnen derzeit nur eine einzige veröffentlichende Mac-Umgebung zur Verfügung steht, entstehen dabei drei konkrete Nachteile: Experimente können den Produktions-Build blockieren, Toolchain- und Cache-Zustände lassen sich schlechter vergleichen, und ein Rollback bleibt möglicherweise ungetestet. Ein Macstripe-Mietknoten kann für diese Übergangsphase die sauberere Lösung sein, weil Sie den Migrationspfad unabhängig aufbauen und nach der Abnahme wieder entfernen können. Für eine dauerhaft hohe Auslastung oder zwingenden Zugriff auf physische Schnittstellen sollten Sie dagegen den Kauf beziehungsweise einen eigenen Knoten prüfen; für zeitlich begrenzte Swift-6.3-Tests und isolierte CI/CD-Verifikation ist die gemietete Umgebung meist die passendere Option.