@FetchRequest SwiftUI-ban — mi ez, Core Data lekérés és mechanizmus

Szerző: IT Sectr Megjelenés: 2026-06-25 Olvasási idő: 8 perc

@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 — property wrapper a Core Data reaktív lekéréséhez SwiftUI-ban
  • Automatikus frissítés UI a Core Data rekordok hozzáadásakor, törlésekor vagy módosításakor
  • Predikátumok és rendezések az inicializátorban vagy property wrapper paraméterekkel állíthatók be
  • managedObjectContext elérhető kell legyen @Environment-en keresztül a View hierarchiában
  • Dinamikus predikátumok lehetővé teszik a szűrési feltételek futásidőben történő megváltoztatását

Mi az @FetchRequest a SwiftUI-ban?

@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.

FetchRequest rendezés és predikátumok

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.

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 ?? "")
        }
    }
}

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 List és dinamikus adatokkal

@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.

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: "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.

Dinamikus predikátumok futásidőben

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.

@FetchRequest kódpéldák

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é.

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)
    }
}

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

Hogyan adjuk át a managedObjectContext-et a @FetchRequest-nek?

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.

Frissíthető a @FetchRequest a View újratöltése nélkü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.

Mi a különbség a @FetchRequest és a @SectionedFetchRequest között?

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.

Hogyan használjam a @FetchRequest-et Relationship-el?

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.

Támogatja a @FetchRequest a lapozást?

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ó

  • @FetchRequest — property wrapper az automatikus reaktív Core Data lekéréshez SwiftUI-ban
  • Rendezés NSSortDescriptor tömb segítségével, szűrés — NSPredicate segítségével
  • Automatikus frissítés UI a Core Data kontextus bármely adatváltozásakor
  • managedObjectContext átadása @Environment-en keresztül a View hierarchiában
  • Dinamikus predikátumok megvalósítása custom init segítségével predikátum paraméterrel
  • CRUD műveletek viewContext-en keresztül, automatikus lista szinkronizációval
  • Használja a @FetchRequest-et Core Data megjelenítéshez, @SectionedFetchRequest-et — csoportosított listákhoz

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.

Projekt megbeszélése

Olvassa el is