Core Data é um framework de gerenciamento de dados da Apple que fornece mapeamento objeto-relacional para iOS, macOS, tvOS e watchOS. Ele automatiza a salvamento, recuperação e filtragem de objetos no aplicativo, funcionando sobre SQLite, XML ou armazenamento binário. De acordo com a Apple Core Data Documentation, o framework usa os conceitos de Managed Object Context e NSPersistentContainer para gerenciar a pilha de persistência.
Principais pontos
Core Data é um framework de gerenciamento de grafo de objetos e persistência que faz parte do Cocoa Touch. Ao contrário do que se pensa, Core Data não é um banco de dados, mas uma camada de gerenciamento de objetos que pode usar SQLite como um de seus armazenamentos. A principal tarefa do Core Data é rastrear alterações de objetos, gerenciar seu ciclo de vida e sincronizar o estado com o disco.
O framework fornece um grafo de objetos onde cada Managed Object é monitorado pelo contexto para detectar alterações. Ao salvar, todos os objetos modificados, adicionados e excluídos são confirmados no armazenamento persistente em uma única transação. Isso elimina a necessidade do desenvolvedor escrever consultas SQL e gerenciar transações manualmente.
De acordo com as estatísticas da Swift Developer Survey (2025), o Core Data é usado em 52% dos aplicativos iOS que trabalham com dados locais. Apesar do surgimento de alternativas modernas (SwiftData, Realm), o Core Data continua sendo o framework principal em projetos Apple existentes devido à sua maturidade e integração profunda com o sistema.
Use Core Data para projetos com modelo de dados de complexidade média, onde são necessários relacionamentos entre objetos, desfazer alterações e cache automático através do mecanismo de faulting.
A arquitetura do Core Data é construída em torno do conceito de Managed Object Context — uma área de trabalho que rastreia todas as alterações de objetos. O contexto suporta desfazer/refazer através do NSUndoManager integrado, permitindo implementar rascunhos e cancelamento de ações sem salvar manualmente snapshots de estado. Ao chamar save(), o contexto confirma todas as alterações em uma única transação no armazenamento persistente, garantindo atomicidade e consistência dos dados.
O modelo de dados do Core Data é definido no arquivo .xcdatamodeld — o editor visual do Xcode onde todas as Entity, seus atributos e relacionamentos são descritos. Na compilação, o modelo é serializado em .momd e carregado através do NSManagedObjectModel.
Entity é uma descrição de tipo de dados, semelhante a uma tabela em SQL. Cada Entity contém um conjunto de Attributes — campos nomeados com tipo de dados (String, Integer, Date, Boolean, Data). Ao contrário do Room, o Core Data requer seleção explícita de tipo para cada atributo através do editor de modelos.
Relationship é uma conexão entre Entity, semelhante a uma chave estrangeira em SQL. Core Data suporta todos os tipos de relacionamentos: um-para-um, um-para-muitos e muitos-para-muitos. Para cada relacionamento é configurada uma Delete Rule (Cascade, Nullify, Deny) — o comportamento ao excluir o objeto relacionado.
| Delete Rule | Comportamento ao excluir | Exemplo de uso |
|---|---|---|
| Cascade | Exclui todos os objetos relacionados | Excluir um pedido junto com seus itens |
| Nullify | Anula o relacionamento inverso | Excluir um autor sem excluir livros |
| Deny | Bloqueia a exclusão se houver objetos relacionados | Proteger contra exclusão de uma categoria com produtos |
Escolher uma Delete Rule é crítico para a integridade dos dados: Cascade sem verificação pode excluir um terço do banco de dados, enquanto Deny pode bloquear a operação com um erro pouco claro. Em código de produção, recomenda-se Nullify com tratamento manual de registros órfãos.
No editor de modelos do Xcode, o desenvolvedor pode definir não apenas Entity e atributos, mas também constraints (restrições de unicidade), índices para acelerar consultas e valores padrão para atributos. Todas as alterações do modelo são compiladas em um arquivo .momd, que é carregado durante a inicialização do NSPersistentContainer. O versionamento de modelo (Model Versioning) permite manter múltiplas versões do esquema e realizar migração entre elas.
NSPersistentContainer é um objeto único que gerencia a pilha Core Data desde iOS 10 e macOS 10.12. Ele encapsula NSManagedObjectModel, NSPersistentStoreCoordinator e NSManagedObjectContext, automatizando o carregamento do modelo e a configuração do armazenamento. Para versões mais antigas, a pilha era construída manualmente, mas isso não é mais recomendado.
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext é o contexto principal vinculado à thread principal. Todas as leituras e atualizações de interface são feitas através dele. Para desempenho, recomenda-se realizar a escrita de dados em um contexto filho em segundo plano com sincronização posterior.
O coordenador NSPersistentStoreCoordinator conecta o modelo ao armazenamento físico em disco. Core Data suporta vários tipos de armazenamento: SQLite (recomendado), Binary e In-Memory. O armazenamento SQLite suporta migrações, backup incremental e resistência a falhas durante operações de escrita.
NSFetchRequest é um objeto que descreve uma consulta ao armazenamento Core Data. Ele contém o nome da Entity, o predicado de filtro, os descritores de ordenação e as configurações de busca. A consulta é executada através de context.fetch(), que retorna um array de NSManagedObject.
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = NSPredicate(format: "age >= %d", 18)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
request.fetchLimit = 50
let results = try context.fetch(request)
NSPredicate suporta condições complexas: LIKE, IN, BETWEEN, CONTAINS[c] (insensível a maiúsculas/minúsculas), SUBQUERY para consultas aninhadas em Entity relacionadas. Core Data também suporta NSFetchedResultsController — uma classe para carregamento reativo de dados em UITableView, que rastreia automaticamente as alterações e atualiza a tabela com seções animadas.
Trabalhar com Core Data em uma aplicação multithread requer conformidade estrita com as regras: NSManagedObject não pode ser passado diretamente entre threads. Cada thread (ou fila) deve usar seu próprio contexto. A abordagem principal é criar um NSManagedObjectContext filho com uma fila privada (NSPrivateQueueConcurrencyType) para escrita e viewContext para leitura.
O contexto filho salva no pai, e então o pai salva no armazenamento em disco. Isso garante que as alterações não bloqueiem a thread principal e que a interface do usuário veja sempre um estado consistente através de mergeChanges ou atualização automática do viewContext ao salvar.
Core Data usa faulting — um mecanismo de carregamento preguiçoso para objetos relacionados. Ao buscar um User sem solicitar seus endereços, os objetos Address relacionados não são carregados até que sejam acessados via notação de ponto. Faulting economiza memória e acelera o carregamento, mas pode causar acessos inesperados ao disco na thread principal se o acesso não for controlado em contextos de segundo plano.
Para multithreading eficiente, use NSBatchInsertRequest e NSBatchDeleteRequest para inserções e exclusões em massa sem carregar objetos na memória — isso é crítico para sincronização de dados com o servidor.
As operações em lote são executadas diretamente no nível do NSPersistentStoreCoordinator, ignorando o contexto e o grafo de objetos. Isso permite inserir 10.000 registros em milissegundos sem criar 10.000 instâncias de NSManagedObject na memória. Após executar uma solicitação em lote, o contexto deve ser atualizado via mergeChangesFromContextDidSaveNotification para que a interface reflita os novos dados. A Apple recomenda operações em lote para carregamento inicial de dados e sincronização noturna com o servidor.
Para rastreamento de alterações no Core Data, usa-se NSPersistentHistoryTracking — um mecanismo que registra cada transação (inserção, atualização, exclusão) em um histórico separado. Ativar o histórico permite sincronizar dados entre diferentes processos e aplicações que trabalham com o mesmo arquivo SQLite, por exemplo entre a aplicação principal e uma Notification Service Extension. A ativação é feita através do NSPersistentStoreDescription com a flag persistentHistoryTrackingKey, e a leitura através do NSPersistentHistoryChangeRequest com filtragem por data e tipo de transação.
Para depuração e análise de desempenho do Core Data, usa-se a ferramenta Core Data Profiler do conjunto Instruments no Xcode no macOS. Ela mostra todas as operações de busca, inserção, exclusão e salvamento com a duração de cada operação e o número de objetos carregados em tabelas e gráficos de linha do tempo. O desenvolvedor pode identificar áreas problemáticas: múltiplas buscas da mesma consulta (falta de cache), vazamentos de objetos fault durante a rolagem da tabela ou bloqueio da thread principal devido ao carregamento síncrono de entidades relacionadas. Recomenda-se executar a criação de perfil em um dispositivo real e não em um simulador, pois o desempenho do simulador não reflete o comportamento real da aplicação em um iPhone ou iPad.
Perguntas frequentes
Core Data não é um banco de dados, mas uma camada de gerenciamento de objetos que pode usar SQLite como armazenamento. Ao contrário do SQLite puro, Core Data rastreia alterações de objetos, gerencia desfazer e fornece um grafo de objetos com faulting e cache. SQLite dá mais controle sobre as consultas, mas requer escrever SQL e gerenciar transações manualmente.
Core Data suporta migração leve (Lightweight Migration) para alterações não destrutivas: adicionar um atributo, renomear, definir um valor padrão. Para alterações complexas, um Mapping Model é criado. A migração leve é ativada pela flag shouldMigrateAutomatically no NSPersistentStoreDescription.
Sim, Core Data integra-se com SwiftUI através do wrapper @FetchRequest para consultas e @ObservedObject para assinatura de alterações. SwiftUI atualiza automaticamente a View quando um ManagedObject muda, tornando Core Data e SwiftUI uma pilha compatível para gerenciamento de estado.
Um fault é um placeholder leve no grafo do Core Data que não contém os dados do objeto relacionado. Quando um fault é definido (via refreshObject:), os dados são descarregados da memória. Quando uma propriedade é acessada, o fault é automaticamente preenchido com dados do armazenamento — este é um mecanismo de carregamento preguiçoso que otimiza o uso de memória.
Para testes, use o tipo de armazenamento In-Memory: NSPersistentStoreDescription com NSInMemoryStoreType. O contêiner é criado com o modelo do bundle de teste. Após cada teste, exclua todos os objetos ou recrie o contêiner — isso garante o isolamento dos casos de teste entre si.
Resumo
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.
Leia também