@FetchRequest SwiftUI-ban — property wrapper a Core Data-ból történő automatikus adatlekéréshez, a felület reaktív frissítésével. A wrapper NSFetchRequest-et fogad szűrő predikátumokkal és rendezésekkel, az eredmény — egy NSManagedObject tömb — automatikusan frissül a Core Data kontextus bármilyen változásakor. A Apple Developer Documentation (2025) szerint a @FetchRequest managedObjectContext-et igényel a SwiftUI környezetben és támogatja a dinamikus predikátumokat, reaktív kapcsolatot biztosítva a Core Data és a felhasználói felület között.
Főbb pontok
@FetchRequest — egy SwiftUI property wrapper, amely FetchRequest-et hoz létre és kezel a Core Data-ból. Inicializáláskor a wrapper elfogadja az entitástípust, egy NSSortDescriptor tömböt a rendezéshez és egy opcionális NSPredicate-et a szűréshez. Az eredmény a megadott NSManagedObject típusú objektumok tömbjeként tárolódik és automatikusan frissül a perzisztencia réteg változásainál.
A @FetchRequest fő jellemzője a reaktivitás. Amikor a Core Data adatai megváltoznak (save, insert, delete, update), a SwiftUI automatikusan újra lekéri és újarajzolja az összes View-t, amely ezt a fetch request-et használja. A fejlesztőnek nem kell manuálisan refresh-t hívnia, feliratkoznia az NSManagedObjectContextDidSaveNotification-ra vagy újratöltenie az adatokat. A SwiftUI kezeli a teljes szinkronizációs ciklust.
A @FetchRequest működéséhez NSManagedObjectContext szükséges, amely a SwiftUI környezetben @Environment(\.managedObjectContext) keresztül érhető el. A kontextus általában az alkalmazás gyökeréből származik, ahol az NSPersistentContainer létrejön. A standard minta — ViewModel vagy App struktúra használata a Core Data stack konfigurálásához és a kontextus átadása a .environment() módosítón keresztül.
A @FetchRequest számos paramétert fogad a lekérés konfigurálásához. SortDescriptors — egy NSSortDescriptor tömb, amely meghatározza a rekordok sorrendjét. Predicate — NSPredicate a szűréshez, például csak a „kész” állapotú feladatok lekérése. Animation — animáció a lista frissítéséhez adatváltozásoknál.
A Core Data predikátumok SQL-szerű kifejezésformátumot használnak: NSPredicate(format: „status == %@”, „completed”). Több feltétel kombinálható AND, OR és NOT segítségével. SortDescriptors meghatározzák a sorrendet: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Több mező szerinti rendezéshez egy deskriptor tömb kerül átadásra — az első főként, a többi másodlagosként érvényesül.
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 ?? "")
}
}
}
A példában a @FetchRequest az összes befejezetlen feladatot (isCompleted == NO) választja ki, előszőr dátum szerint (növekvő), majd prioritás szerint (csökkenő) rendezve. FetchedResults<Task> — egy automatikusan frissülő gyűjtemény, amely tömbként viselkedik a ForEach és List számára. A .default animáció biztosítja a rekordok sima megjelenését/eltűnését változásoknál.
@FetchRequest ideálisan kombinálódik List és ForEach segítségével a dinamikus Core Data listák megjelenítéséhez. A lekérés eredménye (FetchedResults) megfelel a RandomAccessCollection protokollnak, így közvetlenül használható List és ForEach esetén. Rekordok hozzáadásakor, törlésekor vagy módosításakor a lista automatikusan újarajzolódik animációval.
Rekordok törléséhez a kontextus delete metódusát használjuk. Hozzáadáshoz — új NSManagedObject létrehozása és save hívása. Minden változtatás a viewContext-en keresztül történik, amely a @FetchRequest-el együtt biztosítja az adatok konzisztenciáját. Szerkesztéshez @ObservedObject vagy @Bindable használható egy adott Core Data objektumhoz.
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: "hozzáad") { 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()
}
}
Ez a példa teljes CRUD műveletet mutat be @FetchRequest-el. Hozzáadás: Task létrehozása kontextuson keresztül és save(). Törlés: delete() a kontextuson és save(). Frissítés: tulajdonság toggle és save(). Minden save() után a @FetchRequest automatikusan újra kérdezi az adatokat, és a List animációval frissül. Az onDelete és onTapGesture módosítók standard iOS interakciókat biztosítanak.
A @FetchRequest támogatja a dinamikus predikátumokat a predicate paraméteren keresztül, amely futásidőben módosítható. Ehhez létre kell hozni egy @FetchRequest-et változó-predikátummal és át kell adni Binding-en keresztül. Amikor a felhasználó megváltoztatja a szűrőt — például kiválaszt egy feladatkategóriát — a predikátum frissül, és a lekérés automatikusan újraindul.
A dinamikus predikátumok @State vagy @Published tulajdonságon keresztül valósulnak meg, amely Binding-ként kerül átadásra a @FetchRequest inicializátorának. A SwiftUI figyeli ennek a Binding-nek a változását és újra létrehozza az NSFetchRequest-et az új predikátummal, automatikusan frissítve a listát.
Nézzünk egy teljes példát naplóalkalmazásra @FetchRequest-el a bejegyzések lekéréséhez. A keresőűrlap dinamikus predikátumot használ: szöveg beírásakor a FetchRequest automatikusan frissíti az eredményeket, szűrve a bejegyzéseket cím és tartalom alapján. Rendezés — létrehozási dátum szerint, újtól régi felé.
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)
}
}
Napló keresővel: amikor szöveget ír a searchable mezőbe, NSPredicate jön létre CONTAINS[c]-vel (kis/nagybetű érzékenység nélküli keresés) a title és content mezőkben. Az Init elfogadja a searchText-et és létrehozza a FetchRequest-et a megfelelő predikátummal. A Searchable módosító automatikusan frissíti a searchText-et, és a @FetchRequest reagál a predikátum változására és újra kérdezi az adatokat.
Több szűrővel rendelkező összetettebb forgatókönyvekhez kombinálja az NSCompoundPredicate-et AND/OR logikával. A @FetchRequest bármilyen összetettségű predikátumot támogat, beleértve az egymásba ágyazott alkérdezéseket (SUBQUERY) is a relációk szerinti szűréshez. Azonban ne feledje: az összetett predikátumok befolyásolják a teljesítményt — nagy adathalmazokhoz (több mint 10 000 rekord) használja a Core Data indexelést és korlátozza a lekérést fetchLimit-en keresztül.
Gyakran ismételt kérdések
Adja hozzá a @Environment(\.managedObjectContext) var viewContext-ot a gyökér View-hoz és adja át a .environment(\.managedObjectContext, context) módosítón keresztül. Az összes gyermek View, amely @FetchRequest-et használ, automatikusan megkapja a kontextust a környezetből.
Igen, módosítsa a Core Data kontextust: adjon hozzá, töröljön vagy frissítsen egy objektumot és hívja meg a save()-t. A @FetchRequest automatikusan újra lekéri és frissíti a UI-t. Kényszerített frissítéshez save() nélkül használja a viewContext.refreshAllObjects()-et.
A @FetchRequest egy lapos objektumtömböt ad vissza. A @SectionedFetchRequest az eredményeket a megadott key path szerint szakaszokba csoportosítja, hasonlóan a UITableView-hez sectionNameKeyPath-pel. Csoportosított listákhoz szakaszcímekkel használja a @SectionedFetchRequest-et.
Relációk szerinti szűréshez használja a pont jelölést: NSPredicate(format: „category.name == %@”, „Work”). A @FetchRequest automatikusan JOIN-t végez az SQLite-ban. A reláció eléréséhez a kiválasztott objektumon keresztül használja a szokásos NSManagedObject tulajdonságokat.
A @FetchRequest nem támogatja közvetlenül a lapozást, mivel az összes rekord reaktív frissítéssel történő megjelenítésére tervezték. Lapozáshoz használja a NSFetchRequest-et fetchLimit/fetchOffset paraméterekkel és töltse be az adatokat kézzel a lista görgetésekor.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is