Engenharia Estrutural Civil &
Usando dados principais com controle de resultados Nsfetched para dados dinâmicos em Ios
Table of Contents
Introdução: Por que os dados centrais e os resultados do NSFetchedController Matter
No desenvolvimento moderno do iOS, entregar uma interface de usuário fluida e responsiva muitas vezes depende da eficiência com que seu aplicativo lida com dados que mudam ao longo do tempo. Se você está construindo uma fonte social, um gerenciador de tarefas ou um sistema de inventário, os dados exibidos aos usuários raramente são estáticos. Dados essenciais — o gráfico de objeto maduro e a estrutura de persistência da Apple — emparelhado com (FRC) oferece uma solução testada para gerenciar conjuntos de dados dinâmicos e em grande escala, mantendo a interface de usuário em sincronia sem sobrecarga manual.
Este artigo fornece um guia prático e aprofundado para usar os Dados Core com notificações é fundamental. Quando os objetos são inseridos, atualizados ou excluídos, o contexto transmite essas alterações, que é exatamente o que ] aproveita para manter sua interface de usuário consistente.
Para documentação oficial do desenvolvedor, consulte Referência de Base de Dados da Apple.
NSFetchedResultsController: A ponte entre os dados centrais e sua interface
é um objeto de controle projetado para gerenciar eficientemente os resultados retornados de uma solicitação de busca de dados do núcleo, especialmente quando os dados subjacentes são esperados para mudar. Ele monitora o contexto relevante do objeto gerenciado e reporta automaticamente as alterações através de seu protocolo de delegada.
Características-chave
- Tracking de alterações automáticas: O FRC escuta notificações de contexto e traduz-as em callbacks de delegados estruturados (, , ).
- Seccionamento de construção: Ao especificar um , os grupos de controladores obtêm resultados em seções, tornando trivial exibir vistas de tabelas seccionadas ou vistas de coleção.
- Optimização de desempenho: O FRC usa falhas e cache sob o capô. Ele só obtém dados conforme necessário e pode opcionalmente usar uma cache persistente para evitar re-fetching quando o contexto do objeto gerenciado é salvo.
Delegar os Métodos em Detalhe
Para beneficiar totalmente do controlador, você deve implementar o . O padrão mais comum é usar esses callbacks dentro de um ou delegado para atualizar em lote a UI. Por exemplo:
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
@unknown default:
tableView.reloadData()
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
Este padrão garante que a visão de tabela anima as alterações em sincronia com os dados subjacentes, evitando o flicker ou inconsistência.
Implementação passo a passo
Abaixo está um exemplo completo, pronto para a produção usando Swift 5, direcionando iOS 15+. Nós assumiremos uma entidade simples chamada com atributos (String) e (Bool), e um (Data).
1. Configurar a pilha de dados do núcleo
No seu ou um dedicado (comum em aplicativos SwiftUI), crie o recipiente persistente:
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "YourModelName")
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
2. Criar a subclasse NSManagedObject
Use o editor de modelos de dados do Xcode para gerar os arquivos de classe ou criá- los manualmente. Certifique-se de que sua entidade usa a configuração correta do módulo de classe.
3. Configure o pedido de busca e FRC
No seu controlador de view, configure a requisição de busca e inicialize o controlador de resultados obtidos. É melhor executar isso em ou um modelo de view init.
lazy var fetchedResultsController: NSFetchedResultsController<Task> = {
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "dueDate", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
// Optional: limit results with batch size for large datasets
fetchRequest.fetchBatchSize = 20
let controller = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: PersistenceController.shared.container.viewContext,
sectionNameKeyPath: "completionStatus", // e.g., a transient attribute or a computed property
cacheName: nil
)
controller.delegate = self
try? controller.performFetch()
return controller
}()
4. Dirija a visão da tabela com o FRC
Os teus métodos [[FLT: 21]] tornam-se triviais:
func numberOfSections(in tableView: UITableView) -> Int {
fetchedResultsController.sections?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
let task = fetchedResultsController.object(at: indexPath)
configure(cell, with: task)
return cell
}
Observe que nunca chamamos manualmente — os métodos de delegada lidam com cada inserção, exclusão e atualização.
Uso avançado e melhores práticas
Segurança do Rolo
Os contextos de dados principais não são seguros para thread. Use sempre o (que é executado na fila principal) para todas as requisições de busca relacionadas com UI e FRCs. Para o trabalho de fundo, crie um contexto de fila privada e misture alterações no contexto de visualização. Evite usar o mesmo FRC em várias filas.
Cache
O parâmetro pode melhorar o desempenho de lançamento, persistindo seção e informações de objeto. No entanto, se o seu pedido de busca ou alterações de modelo de dados, você deve excluir o cache ()) para evitar corrupção.
Manuseando grandes conjuntos de dados
Use para limitar o número de objetos obtidos na memória. Além disso, considere a configuração somente se você precisar de acesso imediato a cada propriedade. Para dados com relação intensiva, prefetching com pode evitar falhas repetidas.
Integração com SwiftUI
Enquanto é UIKit-centric, você ainda pode usá-lo em SwiftUI, embrulhando-o em um ou usando o invólucro de propriedade mais recente (que usa internamente um mecanismo semelhante). Para dados dinâmicos complexos em SwiftUI, é geralmente suficiente, mas o FRC lhe dá controle fino sobre animações e lotes.
Pistácios comuns e como evitá - los
- Esquecendo : O controlador não executará a busca até que você chame este método. Faça-o uma vez, geralmente logo após a inicialização.
- Não definindo o delegado: Sem um delegado, as alterações não se propagam para a vista da tabela. Sempre chame .
- Descritores de ordenação incorretos: Se o caminho da chave do nome da sua seção não corresponder ao descritor de primeira ordem, as seções podem aparecer fora de ordem. Certifique-se de que o atributo usado em aparece nos descritores de ordenação.
- Usar ao lado do FRC: Chamar enquanto o FRC está animando mudanças pode causar falhas. Deixe os métodos delegados lidar com todas as atualizações de UI.
- Ignorar o contexto de dados principais salva falhas: Se você salvar o contexto e um erro ocorrer, o FRC pode não ser notificado. Sempre lidar com erros e considerar usar em contextos de fundo.
Considerações sobre o desempenho
já é eficiente, mas aqui estão otimizações adicionais:
- Use predicados sabiamente: Um predicado complexo pode retardar a busca inicial. Use atributos indexados onde possível.
- Limite as propriedades obtidas: Se você só precisa de certos atributos, defina no pedido de busca.
- Atualizações do lote: Ao fazer muitas alterações, embrulhe-as em um bloco para reduzir o número de chamadas de delegados.
- Evite falhas desnecessárias: Se você souber que acessará todos os objetos em um conjunto de resultados, use para pré-encontrá-los, mas tenha cuidado com a memória.
Para um mergulho mais profundo no desempenho dos dados principais, consulte Guia de Desempenho de Dados Principais da Apple.
Exemplos do Mundo Real
Exemplo 1: Aplicação de Conversa
Um aplicativo de mensagens exibe uma lista de conversas ordenadas pela mensagem mais recente. Novas mensagens recebidas devem aparecer instantaneamente. Usando um FRC, a visão de contato pode se inscrever para alterações apenas para as entidades de conversa do usuário atual. Seção por data agrupa mensagens em "Hoje", "Ontem", etc.
Exemplo 2: Gestão de Inventário
Um aplicativo de comércio eletrônico mostra produtos em categorias. Quando os níveis de estoque mudam de uma sincronização de fundo, o FRC atualiza automaticamente a UI. Ao configurar para 50, a visualização permanece responsiva mesmo com milhares de itens.
Exemplo 3: Lista de tarefas com categorias
O exemplo clássico: tarefas agrupadas em "Overdue", "Today" e "Upcoming". O pode ser um atributo derivado transitório calculado a partir de e data atual. Certifique-se de que o mesmo valor derivado é usado no descritor de ordenação para evitar erros.
Conclusão
Dominar a combinação de Core Data e é uma pedra angular da construção de aplicativos iOS robustos e dinâmicos. Ao descarregar o pesado levantamento de rastreamento de mudanças e sincronização de interfaces com as estruturas da Apple, você pode se concentrar em criar uma ótima experiência de usuário em vez de escrever código de gerenciamento de dados de placas de caldeira.
Se você está mantendo um aplicativo UIKit legado ou adotando SwiftUI com , os princípios permanecem os mesmos: entender seu gráfico de objeto, configurar os pedidos de busca com cuidado e deixar o controlador de resultados obtidos fazer o que faz melhor. Com as práticas descritas neste artigo — incluindo cache, segurança de thread e ajuste de desempenho — você estará bem equipado para lidar com qualquer conjunto de dados que evolua ao longo do tempo.
Para mais exploração, confira O tutorial de dados principais de Ray Wenderlich e o artigo do NShipster sobre o NSfetchedResultsController.