@FetchRequest in SwiftUI — ein Property Wrapper zum automatischen Abrufen von Daten aus Core Data mit reaktiver Aktualisierung der Benutzeroberfläche. Der Wrapper akzeptiert NSFetchRequest mit Filterprädikaten und Sortierungen, und das Ergebnis — ein Array von NSManagedObject — wird bei Änderungen im Core Data Kontext automatisch aktualisiert. Laut Apple Developer Documentation (2025) benötigt @FetchRequest managedObjectContext in der SwiftUI-Umgebung und unterstützt dynamische Prädikate, wodurch eine reaktive Verbindung zwischen Core Data und der Benutzeroberfläche hergestellt wird.
Wichtige Punkte
@FetchRequest ist ein SwiftUI Property Wrapper, der einen FetchRequest aus Core Data erstellt und verwaltet. Bei der Initialisierung akzeptiert der Wrapper einen Entity-Typ, ein Array von NSSortDescriptor für die Sortierung und ein optionales NSPredicate für die Filterung. Das Ergebnis wird als Array von Objekten des angegebenen NSManagedObject-Typs gespeichert und bei Änderungen in der Persistenzschicht automatisch aktualisiert.
Das Hauptmerkmal von @FetchRequest ist die Reaktivität. Wenn sich Daten in Core Data ändern (save, insert, delete, update), führt SwiftUI automatisch einen erneuten Abruf durch und zeichnet alle Views neu, die diesen Fetch Request verwenden. Der Entwickler muss nicht manuell refresh aufrufen, NSManagedObjectContextDidSaveNotification abonnieren oder Daten neu laden. SwiftUI verwaltet den gesamten Synchronisationszyklus.
Damit @FetchRequest funktioniert, muss ein NSManagedObjectContext in der SwiftUI-Umgebung über @Environment(\.managedObjectContext) verfügbar sein. Der Kontext wird normalerweise vom Anwendungsstamm übergeben, wo ein NSPersistentContainer erstellt wird. Das Standardmuster ist die Verwendung eines ViewModels oder einer App-Struct zur Konfiguration des Core Data Stacks und die Übergabe des Kontexts über den .environment()-Modifikator.
@FetchRequest akzeptiert mehrere Parameter zur Konfiguration des Abrufs. SortDescriptors — ein Array von NSSortDescriptor, das die Reihenfolge der Datensätze bestimmt. Predicate — ein NSPredicate zur Filterung, zum Beispiel nur Aufgaben mit dem Status „erledigt“ abzurufen. Animation — Animation zur Aktualisierung der Liste bei Datenänderungen.
Core Data Prädikate verwenden ein Format von SQL-ähnlichen Ausdrücken: NSPredicate(format: „status == %@“, „completed“). Mehrere Bedingungen können mit AND, OR und NOT kombiniert werden. SortDescriptors definieren die Reihenfolge: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Zum Sortieren nach mehreren Feldern wird ein Array von Deskriptoren übergeben — der erste wird als primärer angewendet, die restlichen als sekundäre.
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 ?? "")
}
}
}
Im Beispiel ruft @FetchRequest alle unerledigten Aufgaben ab (isCompleted == NO), sortiert zuerst nach Datum (aufsteigend), dann nach Priorität (absteigend). FetchedResults<Task> ist eine automatisch aktualisierte Sammlung, die sich für ForEach und List wie ein Array verhält. Die .default-Animation sorgt für ein sanftes Erscheinen/Verschwinden der Datensätze bei Änderungen.
@FetchRequest lässt sich perfekt mit List und ForEach zur Anzeige dynamischer Core Data Listen kombinieren. Das Abrufergebnis (FetchedResults) entspricht dem RandomAccessCollection-Protokoll, sodass es direkt in List und ForEach verwendet werden kann. Beim Hinzufügen, Löschen oder Ändern von Datensätzen wird die Liste automatisch mit Animation neu gezeichnet.
Zum Löschen von Datensätzen wird die Kontextmethode delete verwendet. Zum Hinzufügen von Datensätzen wird ein neues NSManagedObject erstellt und save aufgerufen. Alle Änderungen werden über viewContext durchgeführt, der zusammen mit @FetchRequest die Datenkonsistenz gewährleistet. Zum Bearbeiten wird @ObservedObject oder @Bindable für ein bestimmtes Core Data Objekt verwendet.
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()
}
}
Dieses Beispiel zeigt vollständiges CRUD mit @FetchRequest. Hinzufügen: Erstellen einer Task über den Kontext und save(). Löschen: delete() auf dem Kontext und save(). Aktualisieren: Umschalten einer Eigenschaft und save(). Nach jedem save() ruft @FetchRequest automatisch die Daten erneut ab, und die List wird animiert aktualisiert. Die Modifikatoren onDelete und onTapGesture bieten standardmäßige iOS-Interaktionen.
Betrachten wir ein vollständiges Beispiel einer Tagebuch-Anwendung mit @FetchRequest zum Abrufen von Datensätzen. Das Suchformular verwendet ein dynamisches Prädikat: bei Texteingabe aktualisiert FetchRequest automatisch die Ergebnisse und filtert Datensätze nach Titel und Inhalt. Die Sortierung erfolgt nach Erstellungsdatum, vom neuesten zum ältesten.
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)
}
}
Tagebuch mit Suche: bei Texteingabe in das searchable-Feld wird ein NSPredicate mit CONTAINS[c] (Groß-/Kleinschreibung unwichtige Suche) in den Feldern title und content erstellt. Init akzeptiert searchText und erstellt einen FetchRequest mit dem entsprechenden Prädikat. Der searchable-Modifikator aktualisiert automatisch searchText, und @FetchRequest reagiert auf die Prädikatänderung und ruft die Daten erneut ab.
Für komplexere Szenarien mit mehreren Filtern kombinieren Sie NSCompoundPredicate mit AND/OR-Logik. @FetchRequest unterstützt Prädikate jeder Komplexität, einschließlich verschachtelter Unterabfragen (SUBQUERY) zur Filterung nach Relationship. Beachten Sie jedoch: komplexe Prädikate beeinträchtigen die Leistung — für große Datensätze (über 10.000 Datensätze) verwenden Sie Core Data Indizierung und begrenzen Sie den Abruf über fetchLimit.
@FetchRequest unterstützt dynamische Prädikate über den Parameter predicate, der zur Laufzeit geändert werden kann. Dazu wird ein @FetchRequest mit einem variablen Prädikat erstellt und über Binding übergeben. Wenn der Benutzer den Filter ändert — zum Beispiel eine Aufgabenkategorie auswählt — wird das Prädikat aktualisiert und der Abruf automatisch neu gestartet.
Dynamische Prädikate werden über eine @State- oder @Published-Eigenschaft implementiert, die als Binding an den @FetchRequest-Initialisierer übergeben wird. SwiftUI verfolgt Änderungen an diesem Binding und erstellt den NSFetchRequest mit dem neuen Prädikat neu, wodurch die Liste automatisch aktualisiert wird.
Häufig gestellte Fragen
Fügen Sie @Environment(\.managedObjectContext) var viewContext in der Root-View hinzu und übergeben Sie es über den .environment(\.managedObjectContext, context) Modifikator. Alle untergeordneten Views, die @FetchRequest verwenden, erhalten automatisch den Kontext aus der Umgebung.
Ja, ändern Sie den Core Data Kontext: fügen Sie ein Objekt hinzu, löschen oder aktualisieren Sie es und rufen Sie save() auf. @FetchRequest führt automatisch einen erneuten Abruf durch und aktualisiert die UI. Für eine erzwungene Aktualisierung ohne save() verwenden Sie viewContext.refreshAllObjects().
@FetchRequest gibt ein flaches Array von Objekten zurück. @SectionedFetchRequest gruppiert Ergebnisse nach einem angegebenen Key Path in Abschnitte, ähnlich wie UITableView mit sectionNameKeyPath. Verwenden Sie @SectionedFetchRequest für gruppierte Listen mit Abschnittsüberschriften.
Zum Filtern nach Relationship verwenden Sie die Punkt-Notation: NSPredicate(format: „category.name == %@“, „Work“). @FetchRequest führt automatisch einen JOIN in SQLite durch. Um auf eine Relationship über ein ausgewähltes Objekt zuzugreifen, verwenden Sie die normalen NSManagedObject-Eigenschaften.
@FetchRequest unterstützt keine direkte Paginierung, da es für die Anzeige aller Datensätze mit reaktiver Aktualisierung ausgelegt ist. Für Paginierung verwenden Sie NSFetchRequest mit fetchLimit/fetchOffset und laden Sie Daten manuell beim Scrollen der Liste.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch