SwiftData : Le Guide Ultime de iOS 17 à iOS 26

Publié le · Mis à jour le · 41 min

Wlad
Wlad
Fondateur & Tech Lead Swift

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

AspectCore DataSwiftData

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 :

DeleteRuleComportement

.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'usageRecommandation

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éeSessionSujet

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

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.