@FetchRequest ve SwiftUI — co to je, výběr Core Data a mechanismus

Autor: IT Sectr Publikováno: 2026-06-25 Doba čtení: 8 min

@FetchRequest ve SwiftUI — property wrapper pro automatický výběr dat z Core Data s reaktivní aktualizací rozhraní. Wrapper přijímá NSFetchRequest s predikáty filtrování a řazením, a výsledek — pole NSManagedObject — se automaticky aktualizuje při jakékoli změně v kontextu Core Data. Podle Apple Developer Documentation (2025) vyžaduje @FetchRequest managedObjectContext v prostředí SwiftUI a podporuje dynamické predikáty, což zajišťuje reaktivní propojení mezi Core Data a uživatelským rozhraním.

Hlavní body

  • @FetchRequest — property wrapper pro reaktivní výběr Core Data ve SwiftUI
  • Automatická aktualizace UI při přidávání, mazání nebo změně záznamů v Core Data
  • Predikáty a řazení se nastavují v inicializátoru nebo přes parametry property wrapper
  • managedObjectContext musí být dostupný přes @Environment v hierarchii View
  • Dynamické predikáty umožňují měnit podmínky filtrování za běhu

Co je @FetchRequest ve SwiftUI?

@FetchRequest — je property wrapper SwiftUI, který vytváří a spravuje FetchRequest z Core Data. Při inicializaci wrapper přijímá typ entity, pole NSSortDescriptor pro řazení a volitelný NSPredicate pro filtrování. Výsledek je uložen jako pole objektů zadaného typu NSManagedObject a automaticky se aktualizuje při změnách v perzistenční vrstvě.

Klíčovou vlastností @FetchRequest je reaktivita. Když se data v Core Data změní (save, insert, delete, update), SwiftUI automaticky provede opětovný výběr a překreslí všechna View používající tento fetch request. Vývojář nemusí ručně volat refresh, odebírat se na NSManagedObjectContextDidSaveNotification nebo znovu načítat data. SwiftUI řídí celý cyklus synchronizace.

Pro fungování @FetchRequest je vyžadován NSManagedObjectContext dostupný v prostředí SwiftUI přes @Environment(\.managedObjectContext). Kontext je obvykle předáván z kořene aplikace, kde je vytvořen NSPersistentContainer. Standardní vzor — použití ViewModel nebo struktury App pro konfiguraci Core Data stacku a předání kontextu přes modifikátor .environment().

Řazení a predikáty FetchRequest

@FetchRequest přijímá několik parametrů pro konfiguraci výběru. SortDescriptors — pole NSSortDescriptor určující pořadí záznamů. Predicate — NSPredicate pro filtrování, například výběr pouze úkolů se stavem „dokončeno”. Animation — animace pro aktualizaci seznamu při změnách dat.

Predikáty Core Data používají formát výrazů podobný SQL: NSPredicate(format: „status == %@”, „completed”). Více podmínek lze kombinovat pomocí AND, OR a NOT. SortDescriptors určují pořadí: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Pro řazení podle více polí se předává pole deskriptorů — první se aplikuje jako hlavní, zbývající jako sekundární.

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

V příkladu @FetchRequest vybírá všechny nedokončené úkoly (isCompleted == NO), seřazené nejprve podle data (vzestupně), poté podle priority (sestupně). FetchedResults<Task> — automaticky aktualizovaná kolekce, která se chová jako pole pro ForEach a List. Animace .default zajišťuje plynulé zobrazování/mizení záznamů při změnách.

@FetchRequest s List a dynamickými daty

@FetchRequest se ideálně kombinuje s List a ForEach pro zobrazení dynamických seznamů Core Data. Výsledek výběru (FetchedResults) odpovídá protokolu RandomAccessCollection, takže jej lze použít přímo v List a ForEach. Při přidávání, mazání nebo změně záznamů se seznam automaticky překresluje s animací.

Pro mazání záznamů se používá metoda kontextu delete. Pro přidávání — vytvoření nového NSManagedObject a volání save. Všechny změny se provádějí přes viewContext, který spolu s @FetchRequest zajišťuje konzistenci dat. Pro úpravy se používá @ObservedObject nebo @Bindable pro konkrétní objekt Core Data.

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: "přidat") { 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()
    }
}

Tento příklad demonstruje plné CRUD s @FetchRequest. Přidání: vytvoření Task přes kontext a save(). Mazání: delete() na kontextu a save(). Aktualizace: toggle vlastnosti a save(). Po každém save() @FetchRequest automaticky znovu vyžádá data a List se animovaně aktualizuje. Modifikátory onDelete a onTapGesture poskytují standardní iOS interakce.

Dynamické predikáty za běhu

@FetchRequest podporuje dynamické predikáty přes parametr predicate, který lze měnit za běhu. K tomu je třeba vytvořit @FetchRequest s proměnnou-predikátem a předat ji přes Binding. Když uživatel změní filtr — například vybere kategorii úkolů — predikát se aktualizuje a výběr se automaticky restartuje.

Dynamické predikáty se implementují přes vlastnost @State nebo @Published, která se předává jako Binding do inicializátoru @FetchRequest. SwiftUI sleduje změnu tohoto Binding a znovu vytváří NSFetchRequest s novým predikátem, automaticky aktualizuje seznam.

Příklady kódu @FetchRequest

Podívejme se na úplný příklad aplikace deníku s @FetchRequest pro výběr záznamů. Vyhledávací formulář používá dynamický predikát: při zadávání textu FetchRequest automaticky aktualizuje výsledky a filtruje záznamy podle názvu a obsahu. Řazení — podle data vytvoření, od nejnovějších po nejstarší.

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

Denník záznamů s vyhledáváním: při zadávání textu do searchable pole se vytvoří NSPredicate s CONTAINS[c] (vyhledávání bez rozlišení velikosti písmen) v polích title a content. Init přijímá searchText a vytváří FetchRequest s odpovídajícím predikátem. Modifikátor Searchable automaticky aktualizuje searchText a @FetchRequest reaguje na změnu predikátu a znovu vyžádá data.

Pro složitější scénáře s více filtry kombinujte NSCompoundPredicate s logikou AND/OR. @FetchRequest podporuje predikáty libovolné složitosti, včetně vnořených poddotazů (SUBQUERY) pro filtrování podle relací. Nicméně pamatujte: složité predikáty ovlivňují výkon — pro velké datové sady (více než 10 000 záznamů) použijte indexování Core Data a omezte výběr přes fetchLimit.

Často kladené otázky

Jak předat managedObjectContext do @FetchRequest?

Přidejte @Environment(\.managedObjectContext) var viewContext do kořenového View a předejte jej přes modifikátor .environment(\.managedObjectContext, context). Všechna podřízená View používající @FetchRequest automaticky získají kontext z prostředí.

Lze @FetchRequest aktualizovat bez opětovného načtení View?

Ano, změňte kontext Core Data: přidejte, smažte nebo aktualizujte objekt a zavolejte save(). @FetchRequest automaticky provede opětovný výběr a aktualizuje UI. Pro vynucenou aktualizaci bez save() použijte viewContext.refreshAllObjects().

Jaký je rozdíl mezi @FetchRequest a @SectionedFetchRequest?

@FetchRequest vrací ploché pole objektů. @SectionedFetchRequest seskupuje výsledky podle zadané key path do sekcí, podobně jako UITableView s sectionNameKeyPath. Použijte @SectionedFetchRequest pro seskupené seznamy s nadpisy sekcí.

Jak používat @FetchRequest s Relationship?

Pro filtrování podle relací použijte tečkovou notaci: NSPredicate(format: „category.name == %@”, „Work”). @FetchRequest automaticky provádí JOIN v SQLite. Pro přístup k relaci přes vybraný objekt použijte běžné vlastnosti NSManagedObject.

Podporuje @FetchRequest stránkování?

@FetchRequest přímo nepodporuje stránkování, protože je určen k zobrazení všech záznamů s reaktivní aktualizací. Pro stránkování použijte NSFetchRequest s fetchLimit/fetchOffset a načítejte data ručně při posouvání seznamu.

Shrnutí

  • @FetchRequest — property wrapper pro automatický reaktivní výběr Core Data ve SwiftUI
  • Řazení se nastavuje polem NSSortDescriptor, filtrování — NSPredicate
  • Automatická aktualizace UI při jakékoli změně dat v kontextu Core Data
  • managedObjectContext se předává přes @Environment v hierarchii View
  • Dynamické predikáty se implementují přes custom init s parametrem predikátu
  • CRUD operace se provádějí přes viewContext s automatickou synchronizací seznamu
  • Použijte @FetchRequest pro zobrazení Core Data, @SectionedFetchRequest — pro seskupené seznamy

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také