@AppStorage dans SwiftUI est un property wrapper pour travailler avec UserDefaults qui synchronise automatiquement la valeur avec l'interface utilisateur. Lorsqu'une propriété déclarée avec @AppStorage change, la nouvelle valeur est immédiatement enregistrée dans UserDefaults, et lorsque UserDefaults change de l'extérieur — par un widget ou une extension — la View est automatiquement redessinée. Selon Apple Developer Documentation (2025), @AppStorage prend en charge String, Int, Double, Bool, Data, URL et leurs versions optionnelles, offrant un stockage réactif des paramètres utilisateur sans code d'observation manuel.
Points Clés
@AppStorage est un property wrapper présenté par Apple dans iOS 14 qui lie une propriété de View à une clé dans UserDefaults. Lors de la lecture de la propriété, SwiftUI charge la valeur depuis UserDefaults via la clé spécifiée. Lors de l'écriture, il enregistre la nouvelle valeur et notifie la View qu'elle doit être redessinée.
Avant @AppStorage, les développeurs devaient lire manuellement UserDefaults dans onAppear, s'abonner à UserDefaults.didChangeNotification et mettre à jour @State lors des changements. @AppStorage automatise tout le cycle : une déclaration d'une ligne remplace 15 à 20 lignes de code répétitif. De plus, @AppStorage offre une synchronisation bidirectionnelle — si la valeur UserDefaults change depuis un autre processus (par exemple, App Extension ou Widget), la View reçoit quand même la mise à jour.
Architecturalement, @AppStorage est implémenté comme DynamicProperty, ce qui permet à SwiftUI de suivre les dépendances et de redessiner la View lorsque la valeur observée change. Cela le rend idéal pour stocker les paramètres utilisateur : langue de l'interface, activation/désactivation des fonctionnalités, dernier onglet sélectionné, nom d'utilisateur.
Bien que @AppStorage utilise UserDefaults en interne, les approches de travail avec le stockage sont fondamentalement différentes. UserDefaults est une API de bas niveau qui nécessite une gestion manuelle de la lecture, de l'écriture et des notifications de changement. @AppStorage est une abstraction SwiftUI qui offre un comportement réactif prêt à l'emploi.
UserDefaults est adapté aux opérations ponctuelles : charger les paramètres au démarrage de l'application, écrire des analyses, mettre en cache des jetons. @AppStorage est destiné aux paramètres qui doivent mettre à jour l'UI de façon réactive : interrupteurs de thème, sélection de langue, sauvegarde de l'état de l'interface. Utiliser UserDefaults directement dans une View est un anti-modèle, car la View ne connaît pas les changements sans abonnement supplémentaire.
| Paramètre | @AppStorage | UserDefaults |
|---|---|---|
| Réactivité | Automatique | Nécessite un abonnement aux notifications |
| Boilerplate | 1 ligne par propriété | 15 à 20 lignes par propriété |
| Types | String, Int, Double, Bool, Data, URL | Tous les types + objets archivés |
| Types personnalisés | Via RawRepresentable | Via NSKeyedArchiver |
| App Extension | Synchronisation automatique | Abonnement manuel |
Pour les paramètres simples avec UI réactive @AppStorage est le choix préféré. Pour les données complexes (tableaux, dictionnaires, objets personnalisés), utilisez une combinaison de UserDefaults avec @State et un abonnement manuel aux changements, ou passez à SwiftData / Core Data pour un stockage structuré.
@AppStorage prend en charge les types standards que UserDefaults peut sérialiser directement : String, Int, Double, Bool, Data, URL. Pour chaque type, il existe une version optionnelle (String?, Int?, Double?, Bool?, Data?, URL?) permettant de distinguer « non défini » et « valeur vide ».
Pour stocker des types personnalisés conformes au protocole RawRepresentable, @AppStorage fonctionne également automatiquement. Si une énumération a rawValue de type String ou Int, elle peut être utilisée directement : @AppStorage("theme") var theme: AppTheme = .system. SwiftUI sérialise/désérialise automatiquement la valeur via rawValue.
enum AppTheme: String {
case system, light, dark
}
struct SettingsView: View {
@AppStorage("username") var username: String = "Guest"
@AppStorage("launchCount") var launchCount: Int = 0
@AppStorage("isDarkMode") var isDarkMode: Bool = false
@AppStorage("appTheme") var theme: AppTheme = .system
@AppStorage("lastOpened") var lastOpened: Date? = nil
var body: some View {
Form {
TextField("Username", text: $username)
Toggle("Dark mode", isOn: $isDarkMode)
Text("Lancé \(launchCount) fois")
}
}
}
L'exemple utilise différents types @AppStorage : String avec valeur par défaut « Guest », Int pour un compteur de lancements, Bool pour le thème sombre, énumération AppTheme avec rawValue de type String, et un Date? optionnel pour la dernière ouverture. Chaque propriété est liée à une clé UserDefaults spécifiée comme premier argument. La valeur par défaut est utilisée si la clé est absente du stockage au premier lancement.
L'un des principaux avantages de @AppStorage est l'observation automatique des changements de UserDefaults depuis n'importe quelle source. Si une App Extension ou un Widget modifie une valeur, @AppStorage dans l'application parente reçoit la notification et redessine la View. Ceci est réalisé via le mécanisme KVO (Key-Value Observing) que @AppStorage configure automatiquement sur UserDefaults.didChangeNotification.
En pratique, cela signifie que si l'utilisateur modifie un paramètre dans un Widget (par exemple, active le thème sombre), l'application capte immédiatement le changement. La même synchronisation fonctionne entre l'application principale et Share Extension, Watch App ou Today Widget. Le développeur n'a pas besoin d'écrire de code pour l'échange de données entre processus — @AppStorage le fait automatiquement.
struct ThemeSettingView: View {
@AppStorage("isDarkMode") var isDarkMode: Bool = false
var body: some View {
VStack {
Toggle("Dark Mode", isOn: $isDarkMode)
.onChange(of: isDarkMode) { oldValue, newValue in
print("Mode sombre changé en \(newValue)")
}
}
}
}
Toggle est lié à $isDarkMode via @AppStorage. Lors du basculement, la valeur est automatiquement enregistrée dans UserDefaults sous la clé « isDarkMode ». Le modificateur .onChange permet d'exécuter un effet secondaire lors du changement — par exemple, envoyer des analyses ou mettre à jour l'UI d'autres écrans. Si un Widget modifie la même clé, @AppStorage déclenchera également onChange, assurant la cohérence de l'état.
Examinons un écran de paramètres d'application complet qui utilise @AppStorage pour stocker toutes les configurations. Le formulaire contient des sections avec différents types de paramètres : champs de texte, interrupteurs, compteurs — toutes les valeurs sont automatiquement enregistrées dans UserDefaults.
struct AppSettingsView: View {
@AppStorage("displayName") var displayName = ""
@AppStorage("notificationsEnabled") var notificationsEnabled = true
@AppStorage("maxResults") var maxResults = 25
@AppStorage("selectedTab") var selectedTab = "home"
var body: some View {
NavigationStack {
Form {
Section(header: Text("Profil")) {
TextField("Display name", text: $displayName)
}
Section(header: Text("Préférences")) {
Toggle("Enable notifications",
isOn: $notificationsEnabled)
Stepper("Max results: \(maxResults)",
value: $maxResults,
in: 10...100,
step: 5)
}
Section {
Button("Réinitialiser les paramètres") {
UserDefaults.standard.removePersistentDomain(
forName: Bundle.main.bundleIdentifier!)
}
.tint(.red)
}
}
.navigationTitle("Settings")
}
}
}
Le formulaire contient quatre propriétés @AppStorage de différents types : String pour le nom, Bool pour les notifications, Int pour le nombre de résultats et String pour l'onglet sélectionné. Tous les contrôles sont liés aux propriétés via Binding ($displayName, $notificationsEnabled, etc.). Le bouton « Reset settings » efface tous les UserDefaults en supprimant le domaine de l'application — après quoi @AppStorage revient automatiquement aux valeurs par défaut.
struct SharedSettingsView: View {
let sharedDefaults = UserDefaults(suiteName: "group.com.example.app")
@AppStorage("widgetTheme", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetTheme: String = "système"
@AppStorage("widgetColor", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetColor: String = "bleu"
var body: some View {
Form {
Picker("Widget theme", selection: $widgetTheme) {
Text("Système").tag("system")
Text("Clair").tag("clair")
Text("Sombre").tag("sombre")
}
Picker("Accent color", selection: $widgetColor) {
Text("Bleu").tag("blue")
Text("Vert").tag("vert")
Text("Rouge").tag("rouge")
}
}
}
}
Pour App Group (stockage partagé entre l'application et les extensions), @AppStorage accepte le paramètre store : UserDefaults(suiteName:). Les valeurs sont enregistrées dans le conteneur partagé accessible à l'application principale, Widget, Watch App et autres extensions du même groupe. Un Widget peut lire ces paramètres, et lorsqu'ils changent dans l'application, le Widget se met automatiquement à jour via le mécanisme d'observation UserDefaults.
Questions fréquentes
@State stocke la valeur uniquement en mémoire et se réinitialise au redémarrage de l'application. @AppStorage enregistre la valeur dans UserDefaults et la restaure au lancement suivant. Utilisez @State pour les données temporaires d'écran, @AppStorage pour les paramètres qui doivent survivre à un redémarrage.
Oui, si l'Enum implémente le protocole RawRepresentable avec rawValue de type String ou Int. Exemple : @AppStorage("theme") var theme: AppTheme = . system. SwiftUI sérialise automatiquement l'énumération via rawValue et la restaure au chargement.
Appelez UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) pour le stockage standard ou removeObject(forKey:) pour une clé spécifique. Après effacement, toutes les propriétés @AppStorage reviendront aux valeurs par défaut spécifiées dans la déclaration.
Oui, pour la synchronisation entre l'application et les extensions, utilisez App Group : @AppStorage("key", store: UserDefaults(suiteName: "group.com.example.app")!). Widget, Share Extension et Watch App peuvent lire et écrire dans le même UserDefaults, et les changements sont automatiquement suivis.
@AppStorage utilise UserDefaults, qui est conçu pour de petites quantités de données : paramètres, jetons, compteurs. La limite recommandée est de 100 Ko par application. Pour les données structurées ou volumineuses (tableaux d'objets, fichiers multimédia), utilisez SwiftData, Core Data ou le système de fichiers.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi