@FetchRequest no SwiftUI — o que é, busca de Core Data e mecanismo

Autor: IT Sectr Publicado: 2026-06-25 Tempo de leitura: 8 min

@FetchRequest no SwiftUI — um property wrapper para buscar dados automaticamente do Core Data com atualização reativa da interface. O wrapper aceita NSFetchRequest com predicados de filtro e classificações, e o resultado — um array de NSManagedObject — é atualizado automaticamente em qualquer alteração no contexto do Core Data. Segundo a Apple Developer Documentation (2025), @FetchRequest requer managedObjectContext no ambiente do SwiftUI e suporta predicados dinâmicos, fornecendo uma conexão reativa entre Core Data e a interface do usuário.

Pontos principais

  • @FetchRequest — um property wrapper para busca reativa de Core Data no SwiftUI
  • Atualização automática da UI ao adicionar, excluir ou modificar registros no Core Data
  • Predicados e classificações são definidos no inicializador ou através de parâmetros do property wrapper
  • managedObjectContext deve estar disponível via @Environment na hierarquia de Views
  • Predicados dinâmicos permitem alterar condições de filtro em tempo de execução

O que é @FetchRequest no SwiftUI?

@FetchRequest é um property wrapper do SwiftUI que cria e gerencia um FetchRequest do Core Data. Na inicialização, o wrapper aceita um tipo de entidade, um array de NSSortDescriptor para classificação e um NSPredicate opcional para filtragem. O resultado é armazenado como um array de objetos do tipo NSManagedObject especificado e é atualizado automaticamente quando ocorrem alterações na camada de persistência.

A principal característica do @FetchRequest é a reatividade. Quando os dados no Core Data mudam (save, insert, delete, update), o SwiftUI automaticamente realiza uma nova busca e redesenha todas as Views que usam este fetch request. O desenvolvedor não precisa chamar refresh manualmente, se inscrever no NSManagedObjectContextDidSaveNotification ou recarregar os dados. SwiftUI gerencia todo o ciclo de sincronização.

Para o @FetchRequest funcionar, é necessário um NSManagedObjectContext disponível no ambiente do SwiftUI através de @Environment(\.managedObjectContext). O contexto é normalmente passado da raiz da aplicação, onde um NSPersistentContainer é criado. O padrão comum é usar uma ViewModel ou struct App para configurar a stack do Core Data e passar o contexto através do modificador .environment().

Classificação e predicados do FetchRequest

@FetchRequest aceita vários parâmetros para configurar a busca. SortDescriptors — um array de NSSortDescriptor que determina a ordem dos registros. Predicate — um NSPredicate para filtragem, por exemplo, buscar apenas tarefas com status “concluído”. Animation — animação para atualizar a lista quando os dados mudam.

Os predicados do Core Data usam um formato de expressões semelhantes a SQL: NSPredicate(format: “status == %@”, “completed”). É possível combinar múltiplas condições usando AND, OR e NOT. SortDescriptors definem a ordem: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Para classificar por vários campos, um array de descritores é passado — o primeiro é aplicado como principal, os restantes como secundários.

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

No exemplo, @FetchRequest busca todas as tarefas incompletas (isCompleted == NO), classificadas primeiro por data (ascendente), depois por prioridade (descendente). FetchedResults<Task> é uma coleção que se atualiza automaticamente e se comporta como um array para ForEach e List. A animação .default garante aparecimento/desaparecimento suave dos registros nas alterações.

@FetchRequest com List e dados dinâmicos

@FetchRequest combina perfeitamente com List e ForEach para exibir listas dinâmicas do Core Data. O resultado da busca (FetchedResults) está em conformidade com o protocolo RandomAccessCollection, portanto pode ser usado diretamente em List e ForEach. Ao adicionar, excluir ou modificar registros, a lista é redesenhada automaticamente com animação.

Para excluir registros, usa-se o método do contexto delete. Para adicionar registros, um novo NSManagedObject é criado e save é chamado. Todas as alterações são realizadas através do viewContext, que junto com @FetchRequest garante a consistência dos dados. Para edição, usa-se @ObservedObject ou @Bindable para um objeto específico do 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: "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()
    }
}

Este exemplo demonstra um CRUD completo com @FetchRequest. Adicionar: criar uma Task através do contexto e save(). Excluir: delete() no contexto e save(). Atualizar: alternar uma propriedade e save(). Após cada save(), @FetchRequest busca novamente os dados automaticamente, e a List é atualizada com animação. Os modificadores onDelete e onTapGesture fornecem interações padrão do iOS.

Exemplos de código do @FetchRequest

Vamos ver um exemplo completo de um aplicativo de diário com @FetchRequest para busca de registros. O formulário de pesquisa usa um predicado dinâmico: ao digitar texto, o FetchRequest atualiza automaticamente os resultados, filtrando registros por título e conteúdo. A classificação é por data de criação, do mais recente ao mais antigo.

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

Diário com pesquisa: ao digitar texto no campo searchable, é criado um NSPredicate com CONTAINS[c] (pesquisa sem distinção de maiúsculas/minúsculas) nos campos title e content. Init aceita searchText e cria um FetchRequest com o predicado correspondente. O modificador searchable atualiza automaticamente searchText, e @FetchRequest reage à mudança do predicado e busca novamente os dados.

Para cenários mais complexos com vários filtros, combine NSCompoundPredicate com lógica AND/OR. @FetchRequest suporta predicados de qualquer complexidade, incluindo subconsultas aninhadas (SUBQUERY) para filtrar por relationship. No entanto, lembre-se: predicados complexos afetam o desempenho — para grandes conjuntos de dados (mais de 10.000 registros), use indexação do Core Data e limite a busca através de fetchLimit.

Predicados dinâmicos em tempo de execução

@FetchRequest suporta predicados dinâmicos através do parâmetro predicate, que pode ser alterado em tempo de execução. Para isso, cria-se um @FetchRequest com um predicado variável e passa-se via Binding. Quando o usuário altera o filtro — por exemplo, seleciona uma categoria de tarefas — o predicado é atualizado e a busca é reiniciada automaticamente.

Predicados dinâmicos são implementados através de uma propriedade @State ou @Published, que é passada como Binding para o inicializador do @FetchRequest. O SwiftUI rastreia alterações neste Binding e recria o NSFetchRequest com o novo predicado, atualizando automaticamente a lista.

Perguntas frequentes

Como passar managedObjectContext para @FetchRequest?

Adicione @Environment(\.managedObjectContext) var viewContext na View raiz e passe através do modificador .environment(\.managedObjectContext, context). Todas as Views filhas que usam @FetchRequest receberão automaticamente o contexto do ambiente.

É possível atualizar @FetchRequest sem recarregar a View?

Sim, modifique o contexto do Core Data: adicione, exclua ou atualize um objeto e chame save(). @FetchRequest realizará automaticamente uma nova busca e atualizará a UI. Para uma atualização forçada sem save(), use viewContext.refreshAllObjects().

Qual a diferença entre @FetchRequest e @SectionedFetchRequest?

@FetchRequest retorna um array plano de objetos. @SectionedFetchRequest agrupa resultados por um key path especificado em seções, similar ao UITableView com sectionNameKeyPath. Use @SectionedFetchRequest para listas agrupadas com cabeçalhos de seção.

Como usar @FetchRequest com Relationships?

Para filtrar por relationship, use notação de ponto: NSPredicate(format: “category.name == %@”, “Work”). @FetchRequest realiza automaticamente um JOIN no SQLite. Para acessar uma relationship através de um objeto selecionado, use as propriedades normais de NSManagedObject.

@FetchRequest suporta paginação?

@FetchRequest não suporta paginação diretamente, pois é projetado para exibir todos os registros com atualização reativa. Para paginação, use NSFetchRequest com fetchLimit/fetchOffset e carregue os dados manualmente ao rolar a lista.

Resumo

  • @FetchRequest — um property wrapper para busca reativa automática de Core Data no SwiftUI
  • Classificação definida por um array de NSSortDescriptor, filtragem por NSPredicate
  • Atualização automática da UI em qualquer alteração de dados no contexto do Core Data
  • managedObjectContext é passado através de @Environment na hierarquia de Views
  • Predicados dinâmicos são implementados através de um init personalizado com parâmetro de predicado
  • Operações CRUD são realizadas através do viewContext com sincronização automática da lista
  • Use @FetchRequest para exibir Core Data, @SectionedFetchRequest para listas agrupadas

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também