Dados principais: uabableView com vários nsfetchedResultControllers
-
22-09-2019 - |
Pergunta
O que eu quero fazer é bem simples. No meu uitableViewController, quero carregar dados de vários nsfetchedResultControllers (tenho várias entidades no meu modelo de dados) e colocar dados de cada um em uma seção diferente na visualização da tabela. Por exemplo, todos os itens buscados do primeiro NSFetchedResultController entrariam na seção 0 no UitableView, os itens buscados do outro entram na Seção 1, etc.
O projeto principal do modelo de dados não demonstra como fazer isso. Tudo (principalmente os caminhos do índice) é codificado sem levar em consideração as seções (não há seções no modelo padrão) e tudo é retirado de um único nsfetchedResultController. Existem algum exemplo de projetos ou documentação que demonstra fazer isso?
Obrigado
Solução
Suponha por um momento o seguinte no seu cabeçalho (o código abaixo será um pouco desleixado, minhas desculpas):
NSFetchedResultsController *fetchedResultsController1; // first section data
NSFetchedResultsController *fetchedResultsController2; // second section data
Informe a tabela que deseja ter 2 seções:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2; // you wanted 2 sections
}
Dê os títulos da seção:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [NSArray arrayWithObjects:@"First section title", @"Second section title", nil];
}
Informe a tabela quantas linhas existem por seções:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return [[fetchedResultsController1 fetchedObjects] count];
} else if (section == 1) {
return [[fetchedResultsController2 fetchedObjects] count];
}
return 0;
}
Construa a célula:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... // table cell dequeue or creation, boilerplate stuff
// customize the cell
if (indexPath.section == 0) {
// get the managed object from fetchedResultsController1
// customize the cell based on the data
} else if (indexPath.section == 1) {
// get the managed object from fetchedResultsController2
// customize the cell based on the data
}
return cell;
}
Outras dicas
Estendendo a solução da Giao com dois nsfetchedResultScontrollers - precisamos lembrar que o nosso NSFetchedResultScontroller não conhece nossas duas seções e os NSindexpathes retornados serão sempre para a primeira seção.
Então, quando estamos obtendo um objeto na configuração de células:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
-(void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
NSManagedObject *object = [self.fetchedResults1 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
//use object to configure cell
} else {
NSManagedObject *object = [self.fetchedResults2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
//use object to configure cell
}
}
Atualizando células enquanto o NSFetchedResultScontroller notou algumas alterações:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
NSIndexPath *customIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(controller == self.fetchedResultsController1)?0:1];
NSIndexPath *customNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(controller == self.fetchedResultsController2)?0:1];
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
Vários controladores de busca (e possivelmente várias entidades) são a abordagem errada. A solução correta é usar o sectionNameKeyPath
param para o NSFetchedResultController
Para agrupar os resultados em várias seções. Se você pensar em suas entidades de maneira diferente, talvez elas sejam realmente a mesma entidade e, em vez disso, você pode usar um imóvel ItemType no qual você pode seções (e também deve classificá -la também). Por exemplo, diga que eu tinha lúpulos e grãos de entidades, então eu poderia alterá -los para ingredientes e ter um ingrediente da propriedade INT_16 que eu tenho uma enumeração no código para armazenar os valores hopType = 0
, grainType = 1
. Afinal, todo o ingrediente é apenas um nome e um peso, que ambos compartilham.
Se, no entanto, suas entidades realmente tiverem um conjunto distinto de propriedades, a solução correta é criar uma entidade abstrata pai que possua uma propriedade que você pode usar na seção, por exemplo, Sortorder, Seção ou tipo. Quando você cria um controlador de busca e busca a entidade pai abstrata, na verdade você obtém resultados contendo todas as sub-entidades. Por exemplo, no aplicativo Notes, eles têm uma entidade abstrata noteContainer que possui uma conta e pasta de sub-entrada. Dessa forma, eles podem usar um único controlador de busca para exibir a conta na primeira célula da seção e depois ter todas as pastas nas células a seguir. Por exemplo, todas as notas do iCloud (na verdade é a conta), depois as notas (é a pasta padrão), seguida por todas as pastas personalizadas e depois a pasta de lixo. Eles usam uma propriedade Sortorder e a pasta padrão é 1, as pastas personalizadas são todas 2 e o lixo é 3. Ao adicionar isso como um descritor de classificação que eles podem exibir as células na ordem que desejam. É um pouco diferente do seu requisito, porque eles têm as duas entidades misturadas em seções diferentes, mas você ainda pode usá -lo apenas com diferentes propriedades de classificação.
A moral da história é não lutar contra a estrutura, abraçá-la :-)