@FetchRequest dans SwiftUI — qu'est-ce que c'est, récupération de Core Data et mécanisme

Auteur : IT Sectr Publié le : 2026-06-25 Temps de lecture : 8 min

@FetchRequest dans SwiftUI — un property wrapper pour la récupération automatique de données depuis Core Data avec mise à jour réactive de l'interface. Le wrapper accepte NSFetchRequest avec des prédicats de filtre et des tris, et le résultat — un tableau de NSManagedObject — est automatiquement mis à jour lors de toute modification dans le contexte Core Data. Selon la Apple Developer Documentation (2025), @FetchRequest nécessite managedObjectContext dans l'environnement SwiftUI et prend en charge les prédicats dynamiques, assurant une connexion réactive entre Core Data et l'interface utilisateur.

Points clés

  • @FetchRequest — un property wrapper pour la récupération réactive de Core Data dans SwiftUI
  • Mise à jour automatique de l'interface lors de l'ajout, la suppression ou la modification d'enregistrements dans Core Data
  • Prédicats et tris définis dans l'initialiseur ou via les paramètres du property wrapper
  • managedObjectContext doit être disponible via @Environment dans la hiérarchie des Views
  • Prédicats dynamiques permettent de modifier les conditions de filtre à l'exécution

Qu'est-ce que @FetchRequest dans SwiftUI ?

@FetchRequest est un property wrapper SwiftUI qui crée et gère un FetchRequest depuis Core Data. Lors de l'initialisation, le wrapper accepte un type d'entité, un tableau de NSSortDescriptor pour le tri et un NSPredicate optionnel pour le filtrage. Le résultat est stocké comme un tableau d'objets du type NSManagedObject spécifié et se met automatiquement à jour lors des modifications dans la couche de persistance.

La caractéristique clé de @FetchRequest est la réactivité. Lorsque les données dans Core Data changent (save, insert, delete, update), SwiftUI effectue automatiquement une nouvelle récupération et redessine toutes les Views utilisant cette requête. Le développeur n'a pas besoin d'appeler manuellement refresh, de s'abonner à NSManagedObjectContextDidSaveNotification ou de recharger les données. SwiftUI gère tout le cycle de synchronisation.

Pour que @FetchRequest fonctionne, un NSManagedObjectContext doit être disponible dans l'environnement SwiftUI via @Environment(\.managedObjectContext). Le contexte est généralement passé depuis la racine de l'application, où un NSPersistentContainer est créé. Le modèle standard consiste à utiliser une ViewModel ou une struct App pour configurer la pile Core Data et passer le contexte via le modificateur .environment().

Tri et prédicats de FetchRequest

@FetchRequest accepte plusieurs paramètres pour configurer la récupération. SortDescriptors — un tableau de NSSortDescriptor qui détermine l'ordre des enregistrements. Predicate — un NSPredicate pour le filtrage, par exemple, récupérer uniquement les tâches avec le statut « terminé ». Animation — animation pour mettre à jour la liste lors des changements de données.

Les prédicats Core Data utilisent un format d'expressions de type SQL : NSPredicate(format: « status == %@ », « completed »). On peut combiner plusieurs conditions via AND, OR et NOT. SortDescriptors définissent l'ordre : NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Pour trier par plusieurs champs, on passe un tableau de descripteurs — le premier est appliqué comme principal, les autres comme secondaires.

swift
struct TaskListView: View {
    @Environment(\.managedObjectContext) var viewContext

    @FetchRequest(
        sortDescriptors: [
            NSSortDescriptor(keyPath: \.Task.dueDate, ascending: true),
            NSSortDescriptor(keyPath: \.Task.priority, ascending: false)
        ],
        predicate: NSPredicate(format: "isCompleted == NO"),
        animation: .default
    )
    var tasks: FetchedResults<Task>

    var body: some View {
        List(tasks) { task in
            Text(task.title ?? "")
        }
    }
}

Dans l'exemple, @FetchRequest récupère toutes les tâches incomplètes (isCompleted == NO), triées d'abord par date (croissant), puis par priorité (décroissant). FetchedResults<Task> est une collection à mise à jour automatique qui se comporte comme un tableau pour ForEach et List. L'animation .default assure une apparition/disparition fluide des enregistrements lors des modifications.

@FetchRequest avec List et données dynamiques

@FetchRequest se combine parfaitement avec List et ForEach pour afficher des listes dynamiques Core Data. Le résultat de la récupération (FetchedResults) est conforme au protocole RandomAccessCollection, il peut donc être utilisé directement dans List et ForEach. Lors de l'ajout, la suppression ou la modification d'enregistrements, la liste est automatiquement redessinée avec animation.

Pour supprimer des enregistrements, on utilise la méthode du contexte delete. Pour ajouter des enregistrements, on crée un nouveau NSManagedObject et on appelle save. Toutes les modifications sont effectuées via viewContext, qui avec @FetchRequest assure la cohérence des données. Pour l'édition, on utilise @ObservedObject ou @Bindable pour un objet Core Data spécifique.

swift
struct TaskListWithActions: View {
    @Environment(\.managedObjectContext) var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \.Task.createdAt,
                                               ascending: false)]
    )
    var tasks: FetchedResults<Task>

    var body: some View {
        List {
            ForEach(tasks) { task in
                HStack {
                    Text(task.title ?? "")
                    Spacer()
                    Image(systemName: task.isCompleted
                               ? "checkmark.circle.fill"
                               : "circle")
                }
                .onTapGesture { toggleTask(task) }
            }
            .onDelete(perform: deleteTasks)
        }
        .toolbar {
            Button(systemImage: "plus") { addTask() }
        }
    }

    private func addTask() {
        let newTask = Task(context: viewContext)
        newTask.title = "New task \(tasks.count + 1)"
        newTask.createdAt = Date()
        try? viewContext.save()
    }

    private func toggleTask(_ task: Task) {
        task.isCompleted.toggle()
        try? viewContext.save()
    }

    private func deleteTasks(at offsets: IndexSet) {
        for index in offsets {
            viewContext.delete(tasks[index])
        }
        try? viewContext.save()
    }
}

Cet exemple montre un CRUD complet avec @FetchRequest. Ajout : création d'une Task via le contexte et save(). Suppression : delete() sur le contexte et save(). Mise à jour : basculement d'une propriété et save(). Après chaque save(), @FetchRequest récupère automatiquement les données à nouveau, et la List se met à jour avec animation. Les modificateurs onDelete et onTapGesture offrent des interactions iOS standard.

Exemples de code @FetchRequest

Examinons un exemple complet d'application de journal avec @FetchRequest pour la récupération d'enregistrements. Le formulaire de recherche utilise un prédicat dynamique : lors de la saisie de texte, FetchRequest met automatiquement à jour les résultats, filtrant les enregistrements par titre et contenu. Le tri est par date de création, du plus récent au plus ancien.

swift
struct JournalEntryView: View {
    @Environment(\.managedObjectContext) var viewContext
    @State private var searchText = ""

    private var searchPredicate: NSPredicate? {
        guard !searchText.isEmpty else { return nil }
        return NSPredicate(format: "title CONTAINS[c] %@", searchText)
    }

    @FetchRequest var entries: FetchedResults<JournalEntry>

    init(searchText: String) {
        let sort = [NSSortDescriptor(keyPath: \.JournalEntry.date,
                                           ascending: false)]
        let pred: NSPredicate? = searchText.isEmpty
            ? nil
            : NSPredicate(format: "title CONTAINS[c] %@ OR content CONTAINS[c] %@",
                          searchText, searchText)
        self._entries = FetchRequest(
            sortDescriptors: sort,
            predicate: pred,
            animation: .default
        )
    }

    var body: some View {
        List(entries) { entry in
            VStack(alignment: .leading) {
                Text(entry.title ?? "").font(.headline)
                Text(entry.content ?? "").font(.subheadline)
                    .lineLimit(2)
            }
        }
        .searchable(text: $searchText)
    }
}

Journal avec recherche : lors de la saisie de texte dans le champ searchable, un NSPredicate est créé avec CONTAINS[c] (recherche insensible à la casse) sur les champs title et content. Init accepte searchText et crée un FetchRequest avec le prédicat correspondant. Le modificateur searchable met automatiquement à jour searchText, et @FetchRequest réagit au changement de prédicat et récupère les données à nouveau.

Pour des scénarios plus complexes avec plusieurs filtres, combinez NSCompoundPredicate avec la logique AND/OR. @FetchRequest prend en charge des prédicats de toute complexité, y compris les sous-requêtes imbriquées (SUBQUERY) pour le filtrage par relationship. Cependant, gardez à l'esprit : les prédicats complexes affectent les performances — pour les grands ensembles de données (plus de 10 000 enregistrements), utilisez l'indexation Core Data et limitez la récupération via fetchLimit.

Prédicats dynamiques à l'exécution

@FetchRequest prend en charge les prédicats dynamiques via le paramètre predicate, qui peut être modifié à l'exécution. Pour cela, on crée un @FetchRequest avec un prédicat variable et on le passe via Binding. Lorsque l'utilisateur modifie le filtre — par exemple, sélectionne une catégorie de tâches — le prédicat est mis à jour et la récupération redémarre automatiquement.

Les prédicats dynamiques sont implémentés via une propriété @State ou @Published, qui est passée comme Binding à l'initialiseur de @FetchRequest. SwiftUI suit les modifications de ce Binding et recrée le NSFetchRequest avec le nouveau prédicat, mettant automatiquement à jour la liste.

Foire aux questions

Comment passer managedObjectContext à @FetchRequest ?

Ajoutez @Environment(\.managedObjectContext) var viewContext dans la View racine et passez-le via le modificateur .environment(\.managedObjectContext, context). Toutes les Views enfants utilisant @FetchRequest recevront automatiquement le contexte de l'environnement.

Peut-on mettre à jour @FetchRequest sans recharger la View ?

Oui, modifiez le contexte Core Data : ajoutez, supprimez ou mettez à jour un objet et appelez save(). @FetchRequest effectuera automatiquement une nouvelle récupération et mettra à jour l'interface. Pour une mise à jour forcée sans save(), utilisez viewContext.refreshAllObjects().

Quelle est la différence entre @FetchRequest et @SectionedFetchRequest ?

@FetchRequest retourne un tableau plat d'objets. @SectionedFetchRequest regroupe les résultats par un key path spécifié en sections, similaire à UITableView avec sectionNameKeyPath. Utilisez @SectionedFetchRequest pour les listes groupées avec en-têtes de section.

Comment utiliser @FetchRequest avec les Relationships ?

Pour filtrer par relationship, utilisez la notation pointée : NSPredicate(format: « category.name == %@ », « Work »). @FetchRequest effectue automatiquement une JOIN dans SQLite. Pour accéder à une relationship via un objet sélectionné, utilisez les propriétés normales de NSManagedObject.

@FetchRequest prend-il en charge la pagination ?

@FetchRequest ne prend pas en charge la pagination directement, car il est conçu pour afficher tous les enregistrements avec mise à jour réactive. Pour la pagination, utilisez NSFetchRequest avec fetchLimit/fetchOffset et chargez les données manuellement lors du défilement de la liste.

Résumé

  • @FetchRequest — un property wrapper pour la récupération réactive automatique de Core Data dans SwiftUI
  • Tri défini par un tableau de NSSortDescriptor, filtrage par NSPredicate
  • Mise à jour automatique de l'interface lors de toute modification de données dans le contexte Core Data
  • managedObjectContext est passé via @Environment dans la hiérarchie des Views
  • Prédicats dynamiques implémentés via un init personnalisé avec paramètre de prédicat
  • Opérations CRUD effectuées via viewContext avec synchronisation automatique de la liste
  • Utilisez @FetchRequest pour afficher Core Data, @SectionedFetchRequest pour les listes groupées

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.

Discuter du projet

Lisez aussi