SwiftData-Migrationen: Lightweight vs. Custom, und wann Sie kein V2 brauchen
Das Schema-Migrationskonzept von SwiftData ist eine strukturelle Verbesserung gegenüber Core Data, hat aber eine Falle, in die Teams immer wieder tappen: ein neues VersionedSchema für Änderungen zu deklarieren, die SwiftData ohnehin automatisch über Inline-Defaults erledigen würde. Das Ergebnis ist ein „Duplicate version checksums across stages detected”-Crash auf dem Gerät, obwohl der Code richtig aussah und sauber baute. Das eigentliche Migrationsmodell des Frameworks besteht aus drei Bausteinen (VersionedSchema, MigrationStage, SchemaMigrationPlan) und drei Migrationstypen (automatic lightweight, declared lightweight, custom)1. Die meisten Schemaänderungen sind automatisch. Manche brauchen eine deklarierte Lightweight-Stage. Eine kleine Minderheit braucht eine Custom-Stage mit willMigrate- und didMigrate-Closures.
Dieser Beitrag geht das Migrationsmodell anhand der Apple-Dokumentation durch, benennt die Fälle, die jeder Migrationstyp abdeckt, und behandelt die neue Unterstützung für Klassenvererbung in iOS 26. Der Rahmen lautet „Was deklariere ich selbst und was übernimmt SwiftData für mich”, denn diese Entscheidung bestimmt, ob die Migration sauber ausgeliefert wird oder beim ersten Start abstürzt.
TL;DR
- SwiftData-Migrationen setzen sich aus drei Protokollen zusammen:
VersionedSchema(eine Momentaufnahme der Modelltypen zu einer Version),MigrationStage(ein einzelner Übergang von fromVersion zu toVersion mit den Fällen.lightweightoder.custom) undSchemaMigrationPlan(geordnete Liste der Stages)1. - Das Hinzufügen einer neuen
@Model-Property mit einem Inline-Default (var foo: Bool = false) erfordert kein neuesVersionedSchema. SwiftData behandelt das Hinzufügen automatisch als Lightweight-Migration. Dafür ein V2 zu deklarieren, erzeugt „Duplicate version checksums across stages detected”-Crashes. - Lightweight-Migrationen erledigen: Hinzufügen/Umbenennen/Löschen von Entitäten, Attributen, Beziehungen; Ändern von Beziehungstypen; Deklarieren von
@Attribute(originalName:)zum Nachverfolgen von Umbenennungen; Festlegen von Löschregeln. Die meisten Schemaänderungen passen hierher. - Custom-Migrationen (
MigrationStage.custom(fromVersion:toVersion:willMigrate:didMigrate:)) übernehmen Datentransformationen: das Aufteilen einer Spalte in zwei, das Berechnen abgeleiteter Felder, das Verschieben von Daten zwischen Modellen.willMigratehat den alten Context;didMigratehat den neuen Context. - iOS 26 ergänzt Klassenvererbung für
@Model-Typen2. Schemas, die Vererbung einführen, springen mit einer Lightweight-Stage von der vorherigen Flat-Model-Version auf eine neue Version.
Das dreiteilige Modell
Eine SwiftData-Migration setzt sich aus drei Bausteinen zusammen.
VersionedSchema
Eine Momentaufnahme der Modelltypen zu einer bestimmten Schemaversion1. Das Protokoll verlangt:
static var versionIdentifier: Schema.Version. Ein semantisches Versions-Tripel (Schema.Version(1, 0, 0)).static var models: [any PersistentModel.Type]. Das Array der@Model-Typen in dieser Version.
enum SchemaV1: VersionedSchema {
static let versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var name: String
var createdAt: Date
init(name: String, createdAt: Date) {
self.name = name
self.createdAt = createdAt
}
}
}
Das Muster mit Enum und verschachtelten Typen ist die übliche Konvention. Jedes VersionedSchema kapselt seine Modellklassen in einem eigenen Namespace, sodass mehrere Schemas mit demselben Modellnamen während einer Migration im Code nebeneinander bestehen können.
MigrationStage
Ein einzelner Übergang zwischen zwei VersionedSchema-Typen3. Zwei Fälle:
.lightweight(fromVersion: any VersionedSchema.Type, toVersion: any VersionedSchema.Type). Deklariert einen Übergang, den SwiftData ohne App-Code erledigt. Die Parameter sind dieVersionedSchema-Typen selbst (z. B.SchemaV1.self), nicht roheSchema.Version-Werte..custom(fromVersion:toVersion:willMigrate:didMigrate:). Deklariert einen Übergang mit Code, der vor und/oder nach der Datenmigration läuft. Für die Versionsargumente gelten dieselben Parametertypen wie bei.lightweight.
SchemaMigrationPlan
Die geordnete Liste der Stages, die das Schema von einer beliebigen früheren Version auf die aktuelle bringt1.
enum AppMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[SchemaV1.self, SchemaV2.self, SchemaV3.self]
}
static var stages: [MigrationStage] {
[migrateV1toV2, migrateV2toV3]
}
static let migrateV1toV2 = MigrationStage.lightweight(
fromVersion: SchemaV1.self,
toVersion: SchemaV2.self
)
static let migrateV2toV3 = MigrationStage.custom(
fromVersion: SchemaV2.self,
toVersion: SchemaV3.self,
willMigrate: { context in
// Pre-migration: read old data, prepare it
try context.save()
},
didMigrate: { context in
// Post-migration: backfill new fields
let descriptor = FetchDescriptor<SchemaV3.Item>()
let items = try context.fetch(descriptor)
for item in items {
item.computedField = computeFromExisting(item)
}
try context.save()
}
)
}
Der ModelContainer wird sowohl mit dem aktuellen Schema als auch mit dem Migrationsplan eingerichtet:
let container = try ModelContainer(
for: SchemaV3.Item.self,
migrationPlan: AppMigrationPlan.self,
configurations: ModelConfiguration(...)
)
Beim Erstellen des Containers liest SwiftData die aktuelle Schemaversion des Persistent Store, durchläuft die Stages des Plans von dieser Version vorwärts bis zur aktuellen und wendet jede Stage der Reihe nach an.
Was Lightweight-Migrationen automatisch erledigen
Die meisten Schemaänderungen brauchen keine Custom-Stage1:
- Hinzufügen eines Attributs mit Standardwert.
var foo: Bool = falseauf einem bestehenden@Modelläuft automatisch. - Hinzufügen einer neuen Entität (Modellklasse). Neue Typen erscheinen, sobald ihr
VersionedSchemadas aktuelle ist; vorhandene Daten bleiben erhalten. - Entfernen eines Attributs oder einer Entität. SwiftData verwirft die Spalte oder Tabelle.
- Umbenennen eines Attributs oder einer Entität. Fügen Sie der Property
@Attribute(originalName: "oldName")hinzu, um die Daten zu erhalten; SwiftData ordnet alt zu neu zu. - Ändern eines Beziehungstyps. Single-to-many, many-to-many usw.
- Festlegen von Löschregeln.
@Relationship(deleteRule: .cascade)und ähnliche Ergänzungen sind lightweight.
Für Änderungen aus dieser Liste lautet das richtige Muster, gar kein neues VersionedSchema zu deklarieren, sofern die Modelltypen ansonsten unverändert bleiben. SwiftData führt die Lightweight-Migration automatisch gegen das bestehende Schema durch.
Die Falle: Ein Feld hinzuzufügen erfordert kein V2
Der häufigste Fehler bei SwiftData-Migrationen: Eine Entwicklerin fügt eine neue Property mit einem Inline-Default hinzu (var foo: Bool = false) und deklariert dann ein SchemaV2, das auf dieselben Modelltypen wie SchemaV1 verweist. Der Build ist sauber. Der erste Start auf einem Gerät mit vorhandenen V1-Daten stürzt mit Duplicate version checksums across stages detected ab, weil sowohl SchemaV1 als auch SchemaV2 zur selben Prüfsumme aufgelöst werden (die Modelltypen haben sich nicht auf eine Weise geändert, die SwiftData als unterschiedlich erkennt).
Das korrekte Muster: Lassen Sie das bestehende VersionedSchema unangetastet, fügen Sie die neue Property mit einem Inline-Default zum Modell hinzu und überlassen Sie es der automatischen Lightweight-Migration von SwiftData. Kein MigrationPlan, kein MigrationStage, kein V2 nötig.
// V1 schema
enum SchemaV1: VersionedSchema {
@Model
final class Item {
var name: String
// BEFORE: just these two properties
var createdAt: Date
// AFTER: add a third with inline default
var isFavorite: Bool = false // Lightweight, automatic
}
}
Die Änderung var isFavorite: Bool = false wird ganz ohne MigrationStage-Deklaration ausgeliefert. Der ModelContainer-Initialisierer, der kein migrationPlan: übergibt, funktioniert:
let container = try ModelContainer(
for: SchemaV1.Item.self,
configurations: ModelConfiguration(...)
)
Das V2-Schema ist nur dann erforderlich, wenn eine Änderung nicht lightweight sein kann (eine Datentransformation, ein Modell-Split, eine Umstrukturierung über Vererbung, die Custom-Logik erfordert). In diesen Fällen ist V2 real, und ein SchemaMigrationPlan orchestriert den Übergang.
Wann Custom-Migrationen erforderlich sind
Custom-Migrationen rechtfertigen ihre Komplexität in drei Fällen:
1. Aufteilen eines Felds in mehrere. Ein String-Feld, das "Last, First" enthält, wird zu zwei Feldern, firstName und lastName. Die Migration muss den alten Wert lesen, ihn parsen und die neuen Felder schreiben.
static let migrateV1toV2 = MigrationStage.custom(
fromVersion: SchemaV1.self,
toVersion: SchemaV2.self,
willMigrate: nil,
didMigrate: { context in
let descriptor = FetchDescriptor<SchemaV2.Person>()
let people = try context.fetch(descriptor)
for person in people {
let parts = person.fullName.split(separator: ", ", maxSplits: 1)
person.lastName = String(parts.first ?? "")
person.firstName = String(parts.dropFirst().first ?? "")
}
try context.save()
}
)
Die didMigrate-Closure läuft gegen den Context des neuen Schemas, sodass die neuen Felder zugänglich sind. Das alte fullName muss möglicherweise erst nach dem Befüllen der neuen Felder entfernt werden; die Bereinigung erfolgt als nachgelagerte V2-zu-V3-Stage.
2. Berechnen abgeleiteter Felder. Ein neues @Attribute, das von vorhandenen Daten abhängt, muss zum Migrationszeitpunkt nachträglich befüllt werden.
3. Verschieben von Daten zwischen Modellen. Eine Reorganisation, bei der Daten aus Item zwischen Item und einem neuen Tag-Modell aufgeteilt werden, erfordert Custom-Logik, um Tags aus den alten Daten zuzuweisen.
Das allgemeine Muster: lightweight, wenn sich die Form des Schemas ändert; custom, wenn sich die Form der Daten ändert.
willMigrate vs. didMigrate
Custom-Stages haben zwei Closures, die an unterschiedlichen Punkten aufgerufen werden4:
willMigrate läuft vor der Anwendung der Schemamigration durch SwiftData. Der Model-Context, den die Closure erhält, ist der Context des alten Schemas. Nutzen Sie dies, um Daten zu erfassen, sie zu denormalisieren oder Hilfszustände vorzubereiten, bevor sich das Schema darunter verändert.
didMigrate läuft nach der Schemamigration. Der Model-Context ist der des neuen Schemas. Nutzen Sie dies zum Nachbefüllen neuer Felder, zum Berechnen abgeleiteter Daten oder zum Abschließen der Migration.
Jede Closure kann nil sein, wenn sie nicht benötigt wird. Die meisten Custom-Migrationen nutzen nur didMigrate; willMigrate ist nützlich, wenn die Migration alte Daten lesen muss, die nach der Schemaänderung nicht mehr zugänglich sind.
Die Closure erhält einen ModelContext und kann abrufen, ändern und speichern. Die Closure ist throwing; Fehler propagieren aus der Migration heraus und brechen sie ab.
iOS 26: Klassenvererbung für @Model
iOS 26 führt Klassenvererbung für SwiftData-Modelle ein2. Modelle können nun Eltern-Kind-Beziehungen haben:
@Model
class Vehicle {
var make: String
var year: Int
init(make: String, year: Int) {
self.make = make
self.year = year
}
}
@Model
final class Car: Vehicle {
var doorCount: Int
init(make: String, year: Int, doorCount: Int) {
self.doorCount = doorCount
super.init(make: make, year: year)
}
}
Schemas, die Vererbung einführen, springen mit einer Lightweight-Migrationsstage von der vorherigen Flat-Model-Version auf eine neue Version. Der Übergang läuft automatisch, wenn die Vererbung die bestehenden Properties erhält; neue Felder auf der Unterklasse folgen dem üblichen Muster mit Inline-Default.
Das Muster passt zu Fällen, in denen mehrere @Model-Typen Eigenschaften teilen: ein Vehicle-Elternteil mit den Kindern Car, Truck, Motorcycle; ein Account-Elternteil mit den Kindern CheckingAccount, SavingsAccount. Die gemeinsamen Properties liegen auf dem Elternteil; die Besonderheiten liegen auf den Kindern.
Migrationen testen
Eine Migration, die kompiliert, ist nicht zwangsläufig eine Migration, die ausgeliefert werden kann. Drei Testmuster, die sich vor dem Release lohnen:
1. Round-Trip-Test mit einer Kopie der Produktionsdatenbank. Ziehen Sie eine aktuelle Datenbank in Produktionsform (oder erzeugen Sie synthetische V1-Daten über Tests), öffnen Sie sie mit dem V2-fähigen Container und prüfen Sie, ob die Daten korrekt migrieren. Der Test fängt Fehler in Custom-Migrationen ab, die der Type-Checker nicht erkennen kann.
2. Die alte Version startet weiterhin. Bauen Sie die vorherige App-Version, führen Sie sie einmal aus, um V1-Daten zu erzeugen, bauen Sie dann die neue App-Version und prüfen Sie, ob sie ohne Absturz startet. Der Test fängt die „Duplicate version checksums”-Falle und ähnliche Deklarationsfehler ab.
3. Wiederherstellung nach fehlgeschlagener Migration. Was passiert, wenn die Migration einen Fehler wirft? Das Verhalten von SwiftData hängt von der Konfiguration des Containers ab; bei produktiven Apps sollte ein unbehandelter Migrationsfehler nicht stillschweigend Benutzerdaten löschen. Testen Sie den Fehlerpfad explizit und entscheiden Sie, was die App tut (Rollback, Nachfrage, Wiederherstellung aus einem Backup).
Der Single-Source-of-Truth-Beitrag dieses Clusters behandelt die verwandte Frage, was passiert, wenn ein SwiftData-Store über prozessübergreifende Synchronisierung ersetzt wird. Migrationen sind das Pendant dieses Musters für die lokale Weiterentwicklung.
Migrationen prozessübergreifend ausliefern und Fortschritt sichtbar machen
Zwei operative Details, die die Dokumentation nicht in den Vordergrund stellt, die das SwiftData-Team aber auf der WWDC 2026 hervorgehoben hat5: wo Migrationen laufen, wenn eine App Widgets oder Extensions hat, und wie man eine Fortschritts-UI antreibt, während eine läuft.
Ein Prozess besitzt die Migration. Widgets und Extensions erhalten nicht dieselben Laufzeitressourcen wie die Haupt-App und können eine Migration daher nicht sicher durchführen. Die Empfehlung lautet, den SchemaMigrationPlan1 vollständig aus den Widget- und Extension-Targets herauszuhalten und niemals von dort aus zu migrieren. Wählen Sie einen Prozess, normalerweise die Haupt-App, als Eigentümer der Datenbank. Wenn ein Widget den Container öffnet und der Store auf der Festplatte auf einem unversionierten (älteren) Schema steht, schlägt das Öffnen mit einem Fehler fehl. Behandeln Sie diesen Fehler als Signal dafür, dass eine Migration erforderlich ist: Zeigen Sie eine UI an, die den Benutzer bittet, die Haupt-App zu öffnen, lassen Sie die App die Migration durchführen, und lassen Sie die App die migrierte Schemaversion in einen gemeinsam genutzten UserDefault schreiben. Das Widget liest diesen Wert beim nächsten Mal und öffnet den Container auf der Version, auf die die App bereits migriert hat. Das Muster hält einen einzelnen Schreiber in der Verantwortung und vermeidet, dass zwei Prozesse um die Weiterentwicklung derselben Datei konkurrieren.
Der Fortschritt wird aus der Anzahl der Stages berechnet, nicht aus der Echtzeit. SwiftData stellt keine eigene API für den Migrationsfortschritt bereit5. Um eine Fortschrittsanzeige anzutreiben, zählen Sie die Gesamtzahl der Custom-Migrationsstages im Plan und überschreiben Sie den didMigrate-Handler4 pro Stage so, dass jede Stage ihre Position meldet, „Stage N von M”. Die Zahl spiegelt die abgeschlossenen Stages wider, nicht die verstrichene Zeit, sodass der Balken in diskreten Schritten statt gleichmäßig voranschreitet. Die begleitende Designentscheidung betrifft das, was die App während der Migration anzeigt: Ein nackter Spinner wirkt wie ein Stillstand, und Benutzer springen ab. Halten Sie die App dort, wo die Daten es zulassen, teilweise nutzbar, oder beschreiben Sie zumindest, was jede Stage hinzufügt (die neuen Funktionen, die die Migration freischaltet), damit sich die Wartezeit als Fortschritt auf etwas hin liest und nicht als Leerlauf.
Häufige Fehlerbilder
Drei Muster aus den SwiftData-Fehlerprotokollen:
Ein V2 für eine Änderung deklarieren, die SwiftData automatisch erledigen würde. Der „Duplicate version checksums”-Crash. Lösung: Deklarieren Sie kein neues Schema für das Hinzufügen von Properties mit Inline-Default; lassen Sie SwiftData sie automatisch behandeln.
Custom-Migrationscode, der nicht speichert. Eine didMigrate-Closure, die Entitäten ändert, aber context.save() nicht aufruft, erzeugt eine Migration, die einmal läuft, ihre Arbeit verwirft und bei jedem Start erneut läuft (weil die Migration unvollendet erscheint). Lösung: Jede Closure, die Daten ändert, muss vor der Rückkehr try context.save() aufrufen.
Eine Property ohne @Attribute(originalName:) umbenennen. SwiftData behandelt die neue Property als neu und die alte als gelöscht; vorhandene Daten auf der alten Property gehen verloren. Lösung: Deklarieren Sie @Attribute(originalName: "oldName") var newName: ..., damit SwiftData die Daten über die Umbenennung hinweg zuordnet.
Was dieses Muster für iOS-26+-Apps bedeutet
Drei Erkenntnisse.
-
Standardmäßig ohne
VersionedSchema-Leiter arbeiten. Properties mit Inline-Defaults hinzufügen, ungenutzte Felder löschen, mit@Attribute(originalName:)umbenennen. Alles lightweight und automatisch. DieVersionedSchema-Leiter ist für Änderungen gedacht, die SwiftData wirklich nicht automatisch erledigen kann (Datentransformationen, Custom-Logik, Vererbungsumstrukturierungen). -
MigrationStage.customfür Datentransformationen verwenden, nicht für Änderungen der Schemaform. DiewillMigrate- unddidMigrate-Closures sind für Code gedacht, der auf Daten operiert, nicht um zu deklarieren, dass sich das Schema geändert hat. Änderungen der Schemaform laufen über Lightweight-Stages. -
Migrationen mit echten V1-Daten testen, nicht nur mit synthetischen Testdaten. Migrationen, die bei synthetischen Round-Trips bestehen, können bei Daten in Produktionsform mit Sonderfällen dennoch scheitern (nullable Felder, die das Schema nicht abdeckte, große Datensätze, die ins Timeout laufen usw.). Die Kosten des Testens sind gering; die Kosten eines Migrations-Crashs beim ersten Start sind real.
Der vollständige Apple-Ecosystem-Cluster: typisierte App Intents; MCP-Server; die Routing-Frage; Foundation Models; die Unterscheidung zwischen Laufzeit- und Tooling-LLM; drei Oberflächen; das Single-Source-of-Truth-Muster; zwei MCP-Server; Hooks für die Apple-Entwicklung; Live Activities; die watchOS-Laufzeit; SwiftUI-Interna; RealityKits räumliches Denkmodell; SwiftData-Schemadisziplin; Liquid-Glass-Muster; Multi-Plattform-Auslieferung; die Plattformmatrix; Vision-Framework; Symbol Effects; Core-ML-Inferenz; Writing Tools API; Swift Testing; Privacy Manifest; Barrierefreiheit als Plattform; SF-Pro-Typografie; visionOS-Raummuster; Speech-Framework; worüber ich mich weigere zu schreiben. Der Hub liegt unter der Apple Ecosystem Series. Für den breiteren Kontext rund um iOS mit KI-Agenten siehe den Leitfaden zur iOS-Agent-Entwicklung.
FAQ
Brauche ich immer einen SchemaMigrationPlan?
Nein. Apps mit einer einzigen Schemaversion (das erste Release oder Apps, die bislang nur Lightweight-Änderungen vorgenommen haben) brauchen keinen SchemaMigrationPlan. Der ModelContainer-Initialisierer akzeptiert die Modelle des Schemas direkt. Der Parameter migrationPlan: wird notwendig, sobald zum ersten Mal eine Custom-Migrationsstage deklariert wird (oder sobald die Entwicklerin zum ersten Mal eine explizite Versionsleiter deklarieren möchte).
Woher weiß ich, ob meine Änderung lightweight ist?
Apples Liste der lightweight-fähigen Änderungen1: Hinzufügen von Entitäten/Attributen/Beziehungen, deren Entfernen, Umbenennen mit @Attribute(originalName:), Ändern der Kardinalität von Beziehungen, Festlegen von Löschregeln. Wenn die Änderung in eine dieser Kategorien fällt und die Struktur der Modellklasse ansonsten unverändert bleibt, läuft die Migration automatisch und es ist keine VersionedSchema-Leiter erforderlich. Wenn die Änderung eine Datentransformation erfordert (Berechnen, Aufteilen, Verschieben von Daten), ist sie custom.
Können willMigrate und didMigrate beide gesetzt werden?
Ja. Beide Closures sind einzeln optional, können aber auch beide angegeben werden. willMigrate läuft gegen den Context des alten Schemas, bevor SwiftData migriert; didMigrate läuft danach gegen den Context des neuen Schemas. Die beiden decken Vorbereitung bzw. Abschluss ab.
Was passiert, wenn eine Migration einen Fehler wirft?
Der Fehler propagiert aus der Initialisierung des ModelContainer heraus. Der Container kann nicht geöffnet werden. Das Verhalten der App hängt davon ab, wie die Entwicklerin den Fehler behandelt: Manche Apps zeigen eine Wiederherstellungs-UI, manche versuchen eine Wiederherstellung aus einem Backup, manche löschen den beschädigten Store und beginnen neu. SwiftData löscht bei einem Migrationsfehler keine Benutzerdaten stillschweigend; den Fehler muss die App selbst behandeln.
Wie teste ich eine Migration, ohne Produktionsdaten zu beeinträchtigen?
Bauen Sie ein Test-Target, das einen ModelContainer erstellt, der auf eine temporäre Datei-URL zeigt, befüllen Sie ihn mit V1-Daten und öffnen Sie ihn dann mit dem neuen Container, der den Migrationsplan enthält. Prüfen Sie, ob die migrierten Daten den Erwartungen entsprechen. Das Muster funktioniert sowohl in Unit- als auch in Integrationstests; für möglichst realistische Ergebnisse verwenden Sie eine Kopie einer tatsächlichen Datenbank in Produktionsform.
Funktioniert die Klassenvererbung von iOS 26 mit bestehenden Schemas?
Ja, mit einer Lightweight-Migration. Apps, die Vererbung einführen, springen auf eine neue Schemaversion (z. B. V4) und deklarieren ein MigrationStage.lightweight(fromVersion: V3.self, toVersion: V4.self). Die flachen Properties der Elternklasse bleiben erhalten, und die unterklassenspezifischen Properties werden mit Inline-Defaults hinzugefügt. Die Lightweight-Migration von SwiftData übernimmt die strukturelle Änderung.
Referenzen
-
Apple Developer Documentation:
VersionedSchema- undSchemaMigrationPlan-Protokollreferenzen. Das Migrationsmodell. Siehe auch den verwandten Leitfaden Adopting SwiftData for a Core Data app für die vollständige Darstellung der Schemaevolution. ↩↩↩↩↩↩↩↩ -
Apple Developer: SwiftData: Dive into inheritance and schema migration (WWDC 2025, Session 291). Die Einführung der SwiftData-Klassenvererbung in iOS 26. ↩↩
-
Apple Developer Documentation:
MigrationStagemit den Fällen.lightweight(fromVersion:toVersion:)und.custom(fromVersion:toVersion:willMigrate:didMigrate:). ↩ -
Apple Developer Documentation:
MigrationStage.custom(fromVersion:toVersion:willMigrate:didMigrate:)für die Signatur des Falls. Die Semantik „willMigrate läuft gegen den alten Context” und „didMigrate läuft gegen den neuen Context” ist in der WWDC-2025-Session 291 SwiftData: Dive into inheritance and schema migration dokumentiert, derselben Session, die für die iOS-26-Vererbungsergänzung referenziert wird. ↩↩↩ -
WWDC 2026 SwiftData Group Lab (Session 8017). Paraphrasiert aus einer lokal transkribierten Aufzeichnung des WWDC 2026 SwiftData Group Lab; Apple veröffentlicht keine offiziellen Untertitel für die Labs. Das Gating der Migration für Widgets und Extensions (ein Prozess besitzt die Migration, der Fehlerpfad ist das Migrationssignal, die migrierte Version wird in einem
UserDefaultgespeichert) und die Technik des Fortschritts über die Stage-Anzahl (Überschreiben desdidMigrate-Handlers pro Stage, um Stage N von M zu melden, da keine eigene Fortschritts-API existiert) wurden vom SwiftData-Engineering-Panel beschrieben. Die SymboleSchemaMigrationPlanundMigrationStage.customdidMigratesind gegen die in 1 und 4 zitierte Apple-Developer-Dokumentation bestätigt; das Fehlen einer eigenen Fortschritts-API spiegelt die Darstellung des Panels während des Labs wider. ↩↩