@FetchRequest i SwiftUI — en property wrapper för automatisk hämtning av data från Core Data med reaktiv uppdatering av gränssnittet. Wrappern accepterar NSFetchRequest med filterpredikat och sorteringar, och resultatet — en NSManagedObject-array — uppdateras automatiskt vid varje ändring i Core Data-kontexten. Enligt Apple Developer Documentation (2025) kräver @FetchRequest managedObjectContext i SwiftUI-miljön och stöder dynamiska predikat, vilket ger en reaktiv koppling mellan Core Data och användargränssnittet.
Huvudpunkter
@FetchRequest — är en SwiftUI property wrapper som skapar och hanterar en FetchRequest från Core Data. Vid initiering accepterar wrappern entitetstypen, en NSSortDescriptor-array för sortering och en valfri NSPredicate för filtrering. Resultatet lagras som en array av objekt av den angivna NSManagedObject-typen och uppdateras automatiskt vid ändringar i persistenslagret.
Nyckelfunktionen hos @FetchRequest är reaktivitet. När data i Core Data ändras (save, insert, delete, update) utför SwiftUI automatiskt en ny hämtning och ritar om alla View som använder denna fetch request. Utvecklaren behöver inte manuellt anropa refresh, prenumerera på NSManagedObjectContextDidSaveNotification eller ladda om data. SwiftUI hanterar hela synkroniseringscykeln.
För att @FetchRequest ska fungera krävs NSManagedObjectContext tillgänglig i SwiftUI-miljön via @Environment(\.managedObjectContext). Kontexten skickas vanligtvis från roten av applikationen där NSPersistentContainer skapas. Standardmönstret — användning av ViewModel eller App-struktur för att konfigurera Core Data-stacken och skicka kontexten via .environment()-modifieraren.
@FetchRequest accepterar flera parametrar för att konfigurera hämtningen. SortDescriptors — en NSSortDescriptor-array som bestämmer ordningen på posterna. Predicate — NSPredicate för filtrering, till exempel hämtning av endast uppgifter med status ”avslutad”. Animation — animering för uppdatering av listan vid dataändringar.
Core Data-predikat använder ett SQL-liknande uttrycksformat: NSPredicate(format: ”status == %@”, ”completed”). Flera villkor kan kombineras via AND, OR och NOT. SortDescriptors bestämmer ordningen: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). För sortering efter flera fält skickas en array av deskriptorer — den första tillämpas som primär, de övriga som sekundära.
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 ?? "")
}
}
}
I exemplet väljer @FetchRequest alla ofullständiga uppgifter (isCompleted == NO), sorterade först efter datum (stigande), sedan efter prioritet (fallande). FetchedResults<Task> — en automatiskt uppdaterad samling som beter sig som en array för ForEach och List. .default-animeringen säkerställer smidig visning/försvinnande av poster vid ändringar.
@FetchRequest kombineras idealiskt med List och ForEach för att visa dynamiska Core Data-listor. Hämtningsresultatet (FetchedResults) överensstämmer med RandomAccessCollection-protokollet, så det kan användas direkt i List och ForEach. Vid tillägg, borttagning eller ändring av poster ritas listan automatiskt om med animering.
För borttagning av poster används kontextens delete-metod. För tillägg — skapande av ett nytt NSManagedObject och anrop av save. Alla ändringar utförs via viewContext, som tillsammans med @FetchRequest säkerställer datakonsistens. För redigering används @ObservedObject eller @Bindable för ett specifikt Core Data-objekt.
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: "lägg till") { 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()
}
}
Detta exempel demonstrerar fullständig CRUD med @FetchRequest. Tillägg: skapa Task via kontext och save(). Borttagning: delete() på kontext och save(). Uppdatering: toggle av egenskap och save(). Efter varje save() hämtar @FetchRequest automatiskt data igen och List uppdateras med animering. Modifierarna onDelete och onTapGesture ger standard iOS-interaktioner.
@FetchRequest stöder dynamiska predikat via parametern predicate som kan ändras under körning. För detta måste du skapa @FetchRequest med en variabel-predikat och skicka den via Binding. När användaren ändrar filtret — till exempel väljer en uppgiftskategori — uppdateras predikatet och hämtningen startas automatiskt om.
Dynamiska predikat implementeras via @State- eller @Published-egenskapen, som skickas som Binding till @FetchRequest-initieraren. SwiftUI spårar ändringen av denna Binding och återskapar NSFetchRequest med det nya predikatet, vilket automatiskt uppdaterar listan.
Låt oss titta på ett fullständigt exempel på en dagboksapplikation med @FetchRequest för att hämta poster. Sökformuläret använder ett dynamiskt predikat: när text skrivs in uppdaterar FetchRequest automatiskt resultaten och filtrerar poster efter titel och innehåll. Sortering — efter skapelsedatum, från nyast till äldst.
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)
}
}
Dagbok med sökning: när text skrivs i searchable-fältet skapas NSPredicate med CONTAINS[c] (skiftlägesokänslig sökning) i fälten title och content. Init accepterar searchText och skapar FetchRequest med motsvarande predikat. Searchable-modifieraren uppdaterar automatiskt searchText, och @FetchRequest reagerar på predikatets förändring och hämtar data på nytt.
För mer komplexa scenarier med flera filter, kombinera NSCompoundPredicate med AND/OR-logik. @FetchRequest stöder predikat av valfri komplexitet, inklusive nästlade underfrågor (SUBQUERY) för filtrering efter relationer. Kom dock ihåg: komplexa predikat påverkar prestandan — för stora datamängder (mer än 10 000 poster) använd Core Data-indexering och begränsa hämtningen via fetchLimit.
Vanliga frågor
Lägg till @Environment(\.managedObjectContext) var viewContext i rot-View och skicka den via modifieraren .environment(\.managedObjectContext, context). Alla underordnade View som använder @FetchRequest får automatiskt kontexten från miljön.
Ja, ändra Core Data-kontexten: lägg till, ta bort eller uppdatera objektet och anropa save(). @FetchRequest utför automatiskt en ny hämtning och uppdaterar UI. För tvångsuppdatering utan save() använd viewContext.refreshAllObjects().
@FetchRequest returnerar en platt array av objekt. @SectionedFetchRequest grupperar resultat efter angiven key path i sektioner, liknande UITableView med sectionNameKeyPath. Använd @SectionedFetchRequest för grupperade listor med sektionsrubriker.
För filtrering efter relationer, använd punktnotation: NSPredicate(format: ”category.name == %@”, ”Work”). @FetchRequest utför automatiskt JOIN i SQLite. För åtkomst till relationen via det valda objektet, använd vanliga NSManagedObject-egenskaper.
@FetchRequest stöder inte direkt paginering eftersom det är avsett för att visa alla poster med reaktiv uppdatering. För paginering, använd NSFetchRequest med fetchLimit/fetchOffset och ladda data manuellt vid listrullning.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också