Core Data é um framework da Apple para gerenciar um grafo de objetos em aplicações iOS e macOS. Ele fornece persistência de dados, rastreamento de alterações, operações de desfazer e integração com a UI através de NSFetchedResultsController. Segundo a documentação da Apple Developer (2025), Core Data não é um banco de dados — é uma camada de modelagem de objetos que por padrão usa SQLite como armazenamento persistente para carregar e salvar objetos.
Pontos principais
Core Data é um framework de gerenciamento de grafo de objetos e persistência que faz parte do Cocoa Touch SDK da Apple. Ele fornece uma interface orientada a objetos para trabalhar com dados: o desenvolvedor opera com entidades, atributos e relacionamentos, enquanto o Core Data transforma esses objetos em registros de banco de dados relacional sob o capô.
Core Data foi apresentado no Mac OS X 10.4 Tiger (2005) para macOS e portado para iOS 3.0 (2009). Em mais de 20 anos, o framework evoluiu de uma simples camada de abstração sobre SQLite para um stack completo com suporte a sincronização em nuvem através de NSPersistentCloudKitContainer, multithreading através de gerenciamento automático de contextos e carregamento assíncrono via Swift Concurrency.
De acordo com uma pesquisa de desenvolvedores iOS da Slack Community (2025), Core Data é usado em 68% das aplicações iOS comerciais para armazenamento local de dados. Apesar das críticas por sua complexidade e arquitetura em camadas, o framework continua sendo o padrão para aplicações Apple graças à integração estreita com o sistema, custo zero (embutido no SDK) e suporte a sincronização iCloud.
Um equívoco comum é considerar Core Data um banco de dados. O framework não executa consultas SQL diretamente e não é um SGBD. Core Data é uma camada de gerenciamento de grafo de objetos que pode usar armazenamento SQLite, Binary ou In-Memory para persistência. Analogia: Core Data é como Hibernate ou Entity Framework, mas para o ecossistema Apple, e SQLite por baixo é como MySQL sob Hibernate.
O stack do Core Data consiste em quatro componentes interconectados: NSManagedObjectModel (esquema de dados), NSPersistentStoreCoordinator (coordenador de armazenamento), NSManagedObjectContext (contexto de trabalho) e NSPersistentContainer (um contêiner unificado que combina os três desde iOS 10). NSPersistentContainer automatiza a criação e configuração do stack.
Cada componente executa uma função estritamente definida. NSManagedObjectModel carrega o arquivo .xcdatamodeld com as descrições das entidades. NSPersistentStoreCoordinator conecta o modelo ao arquivo físico de armazenamento (SQLite). NSManagedObjectContext fornece uma área temporária para trabalhar com objetos. O Container unifica tudo em uma única chamada de inicialização.
SQLite (NSSQLiteStoreType) é o armazenamento padrão usado na maioria das aplicações. Os dados são salvos em um único arquivo .sqlite com suporte a transações ACID. Binary (NSBinaryStoreType) é um armazenamento em formato binário para conjuntos de dados pequenos (até algumas centenas de objetos). In-Memory (NSInMemoryStoreType) é um armazenamento temporário em RAM sem persistência em disco, usado para testes e cache.
| Tipo de armazenamento | Formato | Desempenho | Quando usar |
|---|---|---|---|
| SQLite | .sqlite | Alto | Opção padrão para produção |
| Binary | .binary | Médio | Conjuntos de dados pequenos |
| In-Memory | RAM | Máximo | Testes, cache, dados temporários |
| CloudKit | iCloud | Depende da rede | Sincronização entre dispositivos |
O tipo de armazenamento é definido com uma única linha ao inicializar NSPersistentStoreDescription. O desenvolvedor pode mudar de SQLite para In-Memory para testes unitários ou para CloudKit para sincronização iCloud sem alterar o código de manipulação de objetos — Core Data abstrai as diferenças entre tipos de armazenamento através de uma API de contexto unificada.
NSManagedObject é a classe base para todos os objetos Core Data, representando um único registro de entidade. Cada managed object tem um NSManagedObjectID único (identificador persistente), está vinculado a um contexto e rastreia suas alterações via KVO (Key-Value Observing). Desenvolvedores criam subclasses de NSManagedObject para definir propriedades tipadas da entidade.
NSManagedObjectContext é o componente central do Core Data que fornece uma área de trabalho para todas as operações com objetos. O contexto rastreia adições, exclusões e alterações (change tracking), suporta desfazer operações via undoManager e mescla automaticamente alterações de outros contextos ao receber notificações de salvamento.
A regra de filas privadas: NSManagedObjectContext é criado com .privateQueueConcurrencyType ou .mainQueueConcurrencyType. O contexto principal está vinculado à thread principal da UI, enquanto contextos privados executam em filas de fundo. Cada contexto deve ser usado apenas em sua própria fila — acessar um managed object de outra thread causa um crash. parentContext permite organizar uma hierarquia de contextos para escritas assíncronas.
struct CoreDataStack {
let container: NSPersistentContainer
init(name: String) {
container = NSPersistentContainer(name: name)
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Failed to load store: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
func backgroundContext() -> NSManagedObjectContext {
let context = container.newBackgroundContext()
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
return context
}
}
NSPersistentContainer cria automaticamente viewContext (main queue) e fornece newBackgroundContext() para operações em segundo plano. Definir automaticallyMergesChangesFromParent = true faz o viewContext capturar automaticamente as alterações dos contextos em segundo plano quando salvam, atualizando a UI sem necessidade de consultar novamente os dados manualmente.
NSPersistentStoreCoordinator gerencia o armazenamento físico de dados: abre o arquivo, cria tabelas SQLite baseadas no modelo e realiza migrações quando o esquema muda. Ao inicializar NSPersistentStoreDescription com NSSQLiteStoreType, Core Data cria um arquivo SQLite com um esquema correspondente ao modelo .xcdatamodeld.
Core Data não usa consultas SQL padrão via SELECT/INSERT/UPDATE. Em vez disso, ele gera comandos SQL internos baseados no modelo e nas consultas feitas através de NSFetchRequest. O desenvolvedor pode ativar o log SQL com o argumento de inicialização -com.apple.CoreData.SQLDebug 1 para depurar o desempenho das consultas.
Migração leve (Lightweight Migration) é um processo automático de atualização do esquema SQLite ao adicionar novos atributos, alterar flags optional/required ou renomear com renamingID. Migração pesada é necessária para mudanças radicais de esquema como mesclar ou dividir entidades, e é realizada através de um NSMigrationManager personalizado.
let description = NSPersistentStoreDescription()
description.url = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first?
.appendingPathComponent("Model.sqlite")
description.setOption(true as NSNumber,
forKey: NSMigratePersistentStoresAutomaticallyOption)
description.setOption(true as NSNumber,
forKey: NSInferMappingModelAutomaticallyOption)
let container = NSPersistentContainer(name: "AppModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in
if let error = error { print("Migration error: \(error)") }
}
Configurar a migração automática via NSMigratePersistentStoresAutomaticallyOption e NSInferMappingModelAutomaticallyOption permite que Core Data atualize independentemente o arquivo SQLite ao adicionar atributos ou entidades em uma nova versão do modelo. Se a migração não for possível, o store coordinator lança um erro com a descrição do motivo — o desenvolvedor deve então implementar uma migração personalizada via NSMigrationManager.
NSFetchRequest é a ferramenta principal para buscar objetos do Core Data. Uma requisição contém o nome da entidade, predicado (filtro), descritores de ordenação, limite e deslocamento. O resultado é retornado como um array de NSManagedObject ou subclasses tipadas. NSPredicate suporta condições complexas com AND, OR, IN, LIKE e subconsultas.
NSBatchDeleteRequest é uma forma eficiente de deletar objetos em lote sem carregar cada um na memória. A requisição executa no nível SQLite, ignorando o managed object context, e só atualiza o contexto após a conclusão. Requisições batch similares existem para atualizar (NSBatchUpdateRequest) e inserir (NSBatchInsertRequest).
CRUD (Create, Read, Update, Delete) no Core Data é realizado através de métodos do contexto: insert, fetch, save e delete. Todas as alterações são temporárias até que context.save() seja chamado — este método salva as alterações no armazenamento persistente SQLite. Em erro de salvamento, o contexto permanece em seu estado modificado para uma nova tentativa.
let context = container.viewContext
// Criar
let user = User(context: context)
user.id = 42
user.name = "Alice"
// Ler
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)
// Atualizar
results.first?.name = "Alice Updated"
// Excluir
if let first = results.first { context.delete(first) }
// Salvar
try context.save()
Salvar o contexto (context.save()) é uma operação crítica. Se save não for chamado, todas as alterações permanecem apenas em memória. O contexto rastreia o estado hasChanges, que pode ser verificado antes de salvar. Para operações em segundo plano, use newBackgroundContext com seu próprio salvamento, e para a UI, use viewContext com salvamento automático por temporizador ou quando o aplicativo entra em segundo plano.
Primeira prática — use NSPersistentCloudKitContainer para sincronizar dados entre dispositivos do usuário via iCloud. A sincronização em nuvem é ativada adicionando a opção CloudKit à descrição do persistent store. Core Data gerencia automaticamente os conflitos de sincronização e mescla alterações de outros dispositivos.
Segunda prática — evite fetchRequest sem predicado em tabelas grandes. Cada fetch incondicional carrega todos os objetos da entidade na memória, levando a alto consumo de RAM e lentidão da UI. Sempre use predicados e limites. Para paginação, use fetchLimit e fetchOffset no NSFetchRequest.
Terceira prática — configure mergePolicy para resolver conflitos em acesso multithread. NSMergeByPropertyObjectTrumpMergePolicy atualiza propriedades conflitantes do último contexto salvo. NSRollbackMergePolicy descarta alterações do contexto atual em conflito. A escolha da política depende da lógica de negócio da aplicação.
Quarta prática — use NSFetchedResultsController para integração com tabelas e coleções. Ele se inscreve automaticamente nas notificações NSManagedObjectContextDidSave, carrega apenas objetos necessários (faulting) e notifica o delegado sobre inserções, exclusões e movimentos com os index paths apropriados para animação de UITableView.
Faulting é o mecanismo de carregamento preguiçoso do Core Data. Um managed object retornado por uma fetch request está em estado fault — seus atributos não estão totalmente carregados, apenas o identificador. O carregamento completo (fire fault) ocorre no primeiro acesso a qualquer atributo. Relationship prefetching (setRelationshipKeyPathsForPrefetching) carrega objetos relacionados com antecedência, evitando consultas N+1.
extension UserRepository {
func fetchUsersWithPosts() throws -> [User] {
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "isActive == YES")
request.relationshipKeyPathsForPrefetching = ["posts"]
request.returnsObjectsAsFaults = false
request.fetchBatchSize = 20
let context = container.viewContext
return try context.fetch(request)
}
}
fetchBatchSize = 20 faz Core Data carregar dados em lotes de 20 objetos (para exibição em tela), sem carregar toda a tabela de uma vez. A flag returnsObjectsAsFaults = false garante que todos os atributos do usuário sejam carregados imediatamente, útil para exibição direta. O prefetching do relacionamento “posts” evita consultas separadas para cada usuário ao acessar as postagens.
Perguntas frequentes
Não, Core Data é um framework de gerenciamento de grafo de objetos. Ele fornece uma API para trabalhar com objetos, rastrear alterações e persisti-los. O banco de dados sob o capô do Core Data (SQLite por padrão) não deve ser confundido com o próprio framework. Core Data é um ORM, não um SGBD.
Sim, Core Data suporta três tipos de armazenamento: SQLite, Binary e In-Memory. O tipo de armazenamento é definido via NSPersistentStoreDescription. O armazenamento In-Memory não persiste dados em disco e é adequado para testes unitários. O armazenamento Binary é um formato legado para conjuntos compactos de objetos.
Para migração leve, ative NSMigratePersistentStoresAutomaticallyOption e NSInferMappingModelAutomaticallyOption. Para alterações complexas, crie um Mapping Model (.xcmappingmodel) via Xcode. O armazenamento CloudKit (NSPersistentCloudKitContainer) suporta migrações automaticamente ao sincronizar o esquema com o servidor iCloud.
SwiftData é um novo framework da Apple (iOS 17+) construído sobre Core Data usando Swift Macros e Swift Concurrency. SwiftData tem uma sintaxe mais simples: entidades são descritas com o macro @Model, contexto com @Environment(\.modelContext). Sob o capô, SwiftData usa o mesmo stack Core Data e SQLite.
Ative o argumento de inicialização -com.apple.CoreData.SQLDebug 1 — Core Data exibirá todas as consultas SQL e suas durações no console do Xcode. Para perfilamento, use Instruments com o template Core Data, que mostra o número de fault requests, tempos de carregamento de objetos e duração do salvamento do contexto.
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