Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

jsanto

Objective C - guardar em Core data

Mensagens Recomendadas

jsanto

Boas

Estou a ter alguns problemas a guardar utilizando o core data e para um melhor entendimento do meu problema vou passar a explicar o que tenho:

Tenho uma tableview a trabalhar com rows dinâmicas, nesta tableview tenho um botão adicionar (+) na minha barra superior, e sempre que esse botão é pressionado aparece uma tableview dentro de um popover. Cada row desta popovertableview corresponde a diferentes tipos de costum cells, o utilizador escolhe uma qualquer e ela aparecerá inserida na tableview "Mãe". Cada costum cell tem vários textfields, então a ideia é:

  • Escolher uma row na popovertableview e ela será inserida na main.
  • Preencher as textfields.
  • A informação a guardar corresponde ao número de rows inseridas e texto inserido nas textfields.

Quando chamo a popover tableview tenho este método na minha main:

- (IBAction)Add:(id)sender
{
SelectProduct *typeProduct=[[self.storyboard instantiateViewControllerWithIdentifier:@"selectTable"]initWithTableViewTag:self.tableView.tag];
self.popover=[[uIPopoverController alloc]initWithContentViewController:typeProduct];
[popover presentPopoverFromBarButtonItem:buttonAdd permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
typeProduct.popView = self.popover;
typeProduct.cellSelected = self.cellSelected; //cellSelected is core data subclass.
typeProduct.delegate = self;
typeProduct.managedObjectContext = self.managedObjectContext;
}

depois no meu didselectrow da minha popovertableview tenho:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
row = indexPath.row;

if (row == 0)
{
	cellSelected=[NSEntityDescription insertNewObjectForEntityForName:@"CellSave" inManagedObjectContext:self.managedObjectContext];
	cellSelected.nameCellData = @"Olive";  
}

A partir daqui, foi inserida uma row na minha main com as várias textfields para serem preenchidas. Em baixo tenho os métodos relevantes da minha main tableview:

- (void)viewDidLoad
{
[self.tableView registerNib:[uINib nibWithNibName:@"myCostumCellXib" bundle:nil] forCellReuseIdentifier:@"myCostumCell"];

AppDelegate *appDelegate =[[uIApplication sharedApplication] delegate];
self.managedObjectContext=[appDelegate managedObjectContext];

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
	// Replace this implementation with code to handle the error appropriately.
	// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
	NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
	abort();
}

[self fetchedResultsController];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"myCostumCell";

cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.cellSelected = self.cellSelected;
cell.managedObjectContext = self.managedObjectContext;

if (cell == nil)
{
	cell = [[MyCostumCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cellSelected = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.nameCell.text = cellSelected.nameCellData;

if ([cellSelected.nameCellData isEqualToString:@"Olive"])
{
	cell.amount.text = cellSelected.amountData;
	// tenho mais textfields para atribuir mas penso que dá para perceber a ideia.
}
}

O meu metodo fetchedResultsController : ( tambem tenho os outros metodos standard mas penso que este é o mais relevante)

- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil)
{
	return _fetchedResultsController;
}

// Create and configure a fetch request.
NSFetchRequest *fetchRequestCellSave = [[NSFetchRequest alloc] init];
NSEntityDescription *entityCellSave=
[NSEntityDescription entityForName:@"CellSave" inManagedObjectContext:self.managedObjectContext];
[fetchRequestCellSave setEntity:entityCellSave];

// Create the sort descriptors array.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"nameCellData" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequestCellSave setSortDescriptors:sortDescriptors];

_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequestCellSave managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"nameCellData" cacheName:nil];
_fetchedResultsController.delegate = self;
self.fetchedResultsController = _fetchedResultsController;

return _fetchedResultsController;
}

Sempre que preciso de ir para outra tableview, eu percebo que tenho que guardar tudo o que fiz, para isso tenho:

- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];

cellSelected.amountData = cell.amount.text;

//Como anteriormente, tenho mais textfields para atribuir mas como exemplo penso que da para perceber.

[self.managedObjectContext save:nil];
}

Finalmente tenho uma row guardada e o texto na minha textfield "amount" guardado, mas os problemas começam se eu inserir duas rows de uma só vez...isto é, carreguei no + (e uma cell é inserida) e repito o processo...e só depois começo a preencher as textfields. Começo pela primeira row (que foi a segunda a ser inserida, porque a mais recente vai sempre para o topo da tableview) e depois preencho a segunda (que foi a primeira a ser inserida), saio da tableview e volto a entrar e o que acontece é que só uma row é que aparece preenchida, parece que a segunda inserção não é reconhecida, então apago a row vazia...volto a inserir uma nova e já funciona...Porque?!?!

Peço desculpa pelo post comprido mas tinha que detalhar.

Obrigado pela atenção

Editado por Rui Carlos

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
KTachyon

Acho que isto está um pouco confuso. O que é exactamente o teu cellSelected?

Neste método:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"myCostumCell";

   cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
   cell.cellSelected = self.cellSelected;
   cell.managedObjectContext = self.managedObjectContext;

   if (cell == nil)
   {
       cell = [[MyCostumCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
   }
   cellSelected = [self.fetchedResultsController objectAtIndexPath:indexPath];
   cell.nameCell.text = cellSelected.nameCellData;

   if ([cellSelected.nameCellData isEqualToString:@"Olive"])
   {
       cell.amount.text = cellSelected.amountData;
       // tenho mais textfields para atribuir mas penso que dá para perceber a ideia.
   }
}

Na primeira linha estás a atribuir a uma célula o cellSelected do controlador. Em primeiro não percebo porque é que precisas de uma instância do cellSelected no controlador (nem na célula em si). Em segundo, estás a atribuir coisas a uma célula e depois é que vais verificar se ela é nula ou não e gerar a célula. Por estares a trabalhar com o storyboard, isto não te vai dar problemas, mas, nesse caso não devias ter o if (cell == nil).

Mas só depois disto tudo é que vais buscar o cellSelected que seria suposto estar associado a esta célula (bem como os valores). A ideia seria:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"myCostumCell";

   cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

   ClasseDoObjecto *cellSelected = [self.fetchedResultsController objectAtIndexPath:indexPath];

   cell.nameCell.text = cellSelected.nameCellData;

   if ([cellSelected.nameCellData isEqualToString:@"Olive"])
   {
       cell.amount.text = cellSelected.amountData;
       // tenho mais textfields para atribuir mas penso que dá para perceber a ideia.
   }
}

Isto deveria ser suficiente para poderes apresentar os dados das células.

Não olhei muito para o resto, porque ainda falta algum contexto para conseguir averiguar o problema.

Editado por KTachyon
  • Voto 1

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
jsanto

Ola KTachyon

Obrigado por responderes. Sou novo ainda em objective c e existem ainda algumas coisas que me vão ultrapassando :) . Realmente não é preciso verificar se a cell esta nil por estar a trabalhar com o storyboard, mas no meu caso eu criei uma classe e um ficheiro xib para cada cell(porque todas as cells são diferentes), desta forma posso criar os iboutlets á vontade ficando o trabalho mais fácil...não sei se por isso continuo sem ter que verificar se a cell esta nil ou não...tenho?

Em relação ao cellSelected, esta é uma variável da minha classe core data que uso depois para fazer as atribuições no meu cellForRowAtIndexpath.

Eu tenho o core data a funcionar correctamente numa outra tableview, só que nesta eu estou a apresentar várias tableviews (modal presentation), as textfields são logo preenchidas e tem um botão save..É tudo feito num só momento.

Já nesta tableview a funcionalidade é diferente, porque primeiro insiro a celula, e só depois preencho as textfields...o meu problema reside quando insiro 2 rows de uma só vez e preencho as textfields...estas não ficam bem atribuidas a sua respectiva celula.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
KTachyon

Obrigado por responderes. Sou novo ainda em objective c e existem ainda algumas coisas que me vão ultrapassando :) . Realmente não é preciso verificar se a cell esta nil por estar a trabalhar com o storyboard, mas no meu caso eu criei uma classe e um ficheiro xib para cada cell(porque todas as cells são diferentes), desta forma posso criar os iboutlets á vontade ficando o trabalho mais fácil...não sei se por isso continuo sem ter que verificar se a cell esta nil ou não...tenho?

Sim, nesse caso tens.

Em relação ao cellSelected, esta é uma variável da minha classe core data que uso depois para fazer as atribuições no meu cellForRowAtIndexpath.

Eu tenho o core data a funcionar correctamente numa outra tableview, só que nesta eu estou a apresentar várias tableviews (modal presentation), as textfields são logo preenchidas e tem um botão save..É tudo feito num só momento.

Já nesta tableview a funcionalidade é diferente, porque primeiro insiro a celula, e só depois preencho as textfields...o meu problema reside quando insiro 2 rows de uma só vez e preencho as textfields...estas não ficam bem atribuidas a sua respectiva celula.

A questão é que tu só crias o objecto quando seleccionas a célula. Uma célula só é seleccionada se fizeres um tap na mesma. Não tenho a certeza se colocar o foco num campo numa célula também faz com que a célula seja seleccionada, mas tenho as minhas dúvidas.

Aquilo que devias fazer é utilizar o protocolo para lidar com os campos de texto (fazendo do controlador o delegado desses campos) e gerir a informação nesses métodos: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextFieldDelegate_Protocol/UITextFieldDelegate/UITextFieldDelegate.html

  • Voto 1

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.