SwiftData : Le Guide Ultime de iOS 17 à iOS 26
Publié le · Mis à jour le · 41 min
Qu'est-ce que SwiftData ?
SwiftData est un framework de persistance déclaratif qui permet de modéliser et stocker les données de votre application en Swift pur. Il utilise les macros Swift pour transformer des classes ordinaires en modèles persistants, éliminant le besoin de fichiers .xcdatamodeld et de génération de code.
Les caractéristiques principales :
Modélisation en Swift pur avec la macro @Model
Intégration native avec SwiftUI via @Query
Synchronisation CloudKit automatique
Migrations de schéma simplifiées
Concurrence moderne avec @ModelActor
Support multi-plateforme (iOS, macOS, watchOS, tvOS, visionOS)
SwiftData n'est pas un remplacement complet de Core Data, mais plutôt une nouvelle API construite sur ses fondations. Le format de stockage par défaut reste compatible avec Core Data.
SwiftData vs Core Data
| Aspect | Core Data | SwiftData |
|---|---|---|
Modélisation | Fichier .xcdatamodeld | Code Swift (@Model) |
Requêtes | NSFetchRequest | @Query, FetchDescriptor |
Contexte | NSManagedObjectContext | ModelContext |
Concurrence | Queues manuelles | @ModelActor natif |
SwiftUI | Wrappers nécessaires | Intégration native |
Minimum iOS | iOS 3+ | iOS 17+ |
Maturité | 20 ans, très stable | Évolution rapide |
Fonctionnalités | Complet | En rattrapage |
Pour les nouveaux projets ciblant iOS 17+, SwiftData est recommandé. Pour les projets existants ou nécessitant des fonctionnalités avancées (batch operations, faulting), Core Data reste pertinent.
Timeline des évolutions
iOS 17 — Septembre 2023
Lancement initial avec les fondamentaux :
Macro @Model pour la modélisation
@Query pour les requêtes réactives
ModelContainer et ModelContext
Synchronisation CloudKit basique
VersionedSchema pour les migrations
iOS 18 — Septembre 2024
Évolution majeure de l'architecture :
#Unique : contraintes composées avec upsert
#Index : optimisation des requêtes
#Expression : calculs dans les prédicats
History API : tracking des changements
Custom DataStore : backends personnalisés
preserveValueOnDeletion : tombstones
iOS 26 — Juin 2025
Stabilisation et nouvelles fonctionnalités :
Héritage de modèles (class inheritance)
Corrections de bugs critiques (@ModelActor, Codable predicates)
Meilleure intégration Swift 6.2
History sortBy pour pagination optimisée
Premier pas avec SwiftData
La macro @Model
Transformer une classe en modèle persistant ne nécessite qu'une ligne :
La macro @Model génère automatiquement la conformité à PersistentModel et Observable, permettant à SwiftUI de réagir aux changements.
ModelContainer et ModelContext
Le ModelContainer gère le stockage persistant, tandis que le ModelContext représente l'espace de travail pour les opérations CRUD :
Le modifier .modelContainer configure automatiquement le conteneur et injecte le contexte dans l'environnement SwiftUI.
Configuration avancée du container
Pour plus de contrôle, créez le container manuellement :
@Query : requêtes réactives
La macro @Query transforme les requêtes en propriétés réactives :
Les paramètres de @Query permettent le tri, le filtrage et la limitation :
Opérations CRUD
Les opérations de base s'effectuent via le ModelContext :
Modélisation des données
Types supportés
SwiftData supporte nativement :
Primitifs : String, Int, Double, Bool, Date, Data, UUID, URL
Collections : Array, Dictionary, Set
Optionnels : Type?
Enums : avec RawValue ou Codable
Types Codable personnalisés
@Attribute : personnalisation des propriétés
La macro @Attribute permet de configurer le comportement de persistance :
@Relationship : relations entre modèles
SwiftData supporte les relations one-to-one, one-to-many et many-to-many :
Les règles de suppression disponibles :
| DeleteRule | Comportement |
|---|---|
.nullify | Met la relation à nil (défaut) |
.cascade | Supprime les objets liés |
.deny | Bloque si des objets sont liés |
.noAction | Aucune action automatique |
@Transient : propriétés non persistées
Pour les propriétés calculées ou temporaires :
Requêtes et filtrage
FetchDescriptor : requêtes programmatiques
Pour les requêtes en dehors de SwiftUI, utilisez FetchDescriptor :
#Predicate : filtrage type-safe
La macro #Predicate offre un filtrage compilé et type-safe :
Prédicats composés
Combinez plusieurs conditions avec les opérateurs logiques :
#Expression : calculs dans les requêtes (iOS 18)
La macro #Expression permet d'effectuer des calculs directement dans les requêtes :
Contraintes et optimisation (iOS 18)
#Unique : contraintes composées
La macro #Unique garantit l'unicité et effectue des upserts automatiques :
Lors de l'insertion d'un Trip avec les mêmes name/startDate/endDate, SwiftData effectue une mise à jour au lieu de créer un doublon.
#Index : accélérer les requêtes
Créez des index sur les propriétés fréquemment filtrées ou triées :
preserveValueOnDeletion : tombstones
Pour conserver des valeurs après suppression (utile pour l'History API) :
Migrations de schéma
VersionedSchema : versionner ses modèles
Encapsulez chaque version de votre schéma :
SchemaMigrationPlan : plan de migration
Définissez l'ordre des migrations et les étapes custom :
Migrations custom
Pour les transformations complexes :
De unversioned à versioned
Si votre app est déjà en production sans VersionedSchema :
CloudKit Sync
Configuration automatique
Activez iCloud dans votre projet et configurez le container :
Options de base de données CloudKit :
.automatic : Sync automatique avec le container par défaut
.private("container.id") : Container privé spécifique
.none : Pas de sync CloudKit
Limitations importantes
CloudKit avec SwiftData a des contraintes :
.unique n'est PAS supporté avec CloudKit (génère des doublons)
Pas de sync de relations optionnelles vides
Pas de support shared/public databases
Conflits résolus par "last write wins"
Debug CloudKit
Activez les logs pour diagnostiquer :
Concurrence et @ModelActor
Le problème : @Query bloque MainActor
@Query et ModelContext s'exécutent sur le MainActor. Pour des opérations lourdes, cela bloque l'UI :
@ModelActor : opérations en background
Créez un actor dédié pour les opérations lourdes :
Utilisation depuis SwiftUI
PersistentIdentifier : passer entre actors
Les modèles ne sont pas Sendable. Utilisez leurs identifiants :
History Tracking (iOS 18)
Activer le tracking d'historique
L'historique est activé par défaut avec DefaultStore. Utilisez preserveValueOnDeletion pour conserver les identifiants des éléments supprimés :
Récupérer l'historique des changements
Cas d'usage : synchronisation serveur
Custom DataStore (iOS 18)
Concepts clés
iOS 18 permet de remplacer le backend SQLite par n'importe quel système de stockage via le protocole DataStore :
DataStoreConfiguration : décrit le store
DataStoreSnapshot : représente les valeurs d'un modèle
DataStore : implémente fetch/save
Créer un JSONStore
Exemple simplifié d'un store basé sur JSON :
Héritage de modèles (iOS 26)
Quand utiliser l'héritage
L'héritage est approprié quand :
Les modèles forment une hiérarchie naturelle (is-a relationship)
Ils partagent des propriétés communes
Vous voulez des requêtes polymorphiques
Requêtes polymorphiques
Utilisez le mot-clé is dans les prédicats :
Performance : attention au Single Table Inheritance
SwiftData stocke tous les sous-types dans une seule table (Wide Table). Cela peut impacter les performances avec beaucoup de sous-classes différentes, des propriétés très différentes entre sous-classes, ou des volumes de données importants.
Pour les hiérarchies complexes, préférez la composition avec des relations.
Debugging avancé
Arguments de lancement Core Data
Ajoutez ces arguments dans votre scheme (Edit Scheme → Arguments) :
Inspection de la base SQLite
Localisez et inspectez le fichier de données :
Instruments : Core Data template
- Product → Profile (Command+I)
- Choisir "Core Data"
- Les instruments disponibles :
Core Data Fetches : durée et fréquence des fetch
Core Data Saves : opérations de sauvegarde
Core Data Faults : lazy loading
Core Data Cache Misses : accès non cachés
Bonnes pratiques
Architecture recommandée : Repository Pattern
Isolez SwiftData derrière une abstraction :
Tests unitaires avec in-memory store
Previews Xcode
Créez un container de preview dédié :
Pièges courants et solutions
Bug @ModelActor view updates (fix iOS 26)
Avant iOS 26, les modifications via @ModelActor ne déclenchaient pas toujours les updates SwiftUI :
iOS 26 corrige ce bug de manière rétrocompatible jusqu'à iOS 17.
Codable dans predicates (fix iOS 26)
Avant iOS 26, utiliser des propriétés Codable dans les predicates ne fonctionnait pas :
CloudKit + .unique incompatibles
Cascade deletion qui ne fonctionne pas
Bug connu : .cascade ne supprime pas toujours les enfants :
Alternatives et interop
Quand choisir une alternative
| Cas d'usage | Recommandation |
|---|---|
Nouveau projet iOS 17+ simple | SwiftData |
Projet existant Core Data | Rester sur Core Data |
Sync serveur custom | GRDB ou Realm |
Base partagée cross-platform | SQLite (GRDB) |
Performance critique | Core Data ou GRDB |
Features avancées (batch, faulting) | Core Data |
Alternatives populaires
GRDB : Wrapper SQLite puissant, très performant
Realm : Solution complète avec sync, cross-platform
Blackbird : SwiftUI-first, simple et léger
Cohabitation SwiftData + Core Data
Possible mais complexe. Les identifiants ne sont pas compatibles. Approche recommandée : migration progressive — garder Core Data pour les features critiques, nouveaux modèles en SwiftData, migrer progressivement quand SwiftData mature.
Ressources officielles
Documentation Apple
WWDC Sessions
| Année | Session | Sujet |
|---|---|---|
2023 | Meet SwiftData | Introduction |
2023 | Build an app with SwiftData | Tutoriel pratique |
2023 | Model your schema with SwiftData | Modélisation |
2024 | What's new in SwiftData | #Unique, #Index, History |
2024 | Create a custom data store | DataStore protocol |
2024 | Track model changes with history | History API |
2025 | Dive into inheritance and migration | Héritage iOS 26 |
Blogs recommandés
FatBobMan (Xu Yang) — Analyses techniques profondes
Donny Wals — Tutoriels pratiques
Use Your Loaf — Références concises
SwiftData représente l'avenir de la persistance sur les plateformes Apple. Malgré une jeunesse qui se traduit par quelques limitations, le framework évolue rapidement et devient de plus en plus viable pour les applications en production. En maîtrisant les concepts de ce guide, vous êtes prêt à l'adopter sereinement dans vos projets.