PDA

View Full Version : [Resolved] UITableView Problem




larswik
Aug 16, 2012, 01:30 AM
I have a problem with a UITableView. I included 2 photos a before and after to help illustrate the problem better. The tableView performs like it is supposed to until I delete a row from section 0. When it reloads the tableview the the 'detailTextLabel' which should have been deleted show up in section 1 of that tableview.

Out of the 3 sections in that tableview only section 0 should have a detailedTextLable. But you can see that after I delete a row from section 0 it reloads incorrectly.

If I stop the program and restart it everything loads in the way it should. I think the problem has to do with the reload of the stored cells. Depending on what section is selected I create ether a UITableViewCellStyleDefault or UITableViewCellStyleSubtitle

I did solve this problem but the way I solved it I know is wrong (this code is before my solved code). When the view is entered again, in the Method viewWillAppear I remove the tableview from the superview and re initilize a new tableview with the same name and everything load just fine. But I should not have to do that.

Is there a way to just delete the whole index that stores the cell so it can create a new NSIndex from scratch populates the new tableview?


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

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.3];

}
if (tableView == staticSkillsTableView) {
cell.textLabel.text = [staticSkills objectAtIndex:indexPath.row];
int x = [[staticSkills objectAtIndex:indexPath.row]length];
if (x > 18) {
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:15];
}
else{
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:18];
}
}
if (tableView == battleTableView) {
if (indexPath.section == 0) {
NSDictionary *getLevel = [characterLoadInfo objectForKey:@"combatroundsSaved"];
NSDictionary *getname = [NSDictionary dictionaryWithDictionary:[getLevel objectForKey:[nameArrayForTableView objectAtIndex:indexPath.row]]];
NSString *level = [NSString stringWithString:[getname objectForKey:@"level"]];

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.3];
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:15];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = [NSString stringWithFormat:[nameArrayForTableView objectAtIndex:indexPath.row], indexPath.row];
cell.detailTextLabel.text = [detailedNameArrayForTableView objectAtIndex:indexPath.row];
if ([level isEqualToString:@"0"]) {
cell.detailTextLabel.textColor = [UIColor redColor];
}
else{
cell.detailTextLabel.textColor = [UIColor blackColor];
}

}
}
if (indexPath.section == 1) {
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:15];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = [NSString stringWithFormat:[usedSkillsArray objectAtIndex:indexPath.row], indexPath.row];
}

if (indexPath.section == 2) {
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:20];
NSString *itemName = [NSString stringWithFormat:[itemListArray objectAtIndex:indexPath.row], indexPath.row];
NSArray *itemBonusArray = [NSArray arrayWithArray:[itemListDict objectForKey:itemName]];
NSString *itemBonus = [NSString stringWithFormat:@"%@", [itemBonusArray objectAtIndex:0]];

if (![itemBonus isEqualToString:@"0"]) {
NSString *writeToCell = [NSString stringWithFormat:@"%@ +%@",itemName, itemBonus];
cell.textLabel.text = writeToCell;
}
else{
NSString *writeToCell = [NSString stringWithFormat:@"%@",itemName];
cell.textLabel.text = writeToCell;
}
}
return cell;
}



MattInOz
Aug 16, 2012, 02:22 AM
Your only using a single Reuse Identifier.
And the tableview wants to be as efficient as it can.

So after you delete a cell in section 0 there is a spare cell in your re-use queue that looks like it did when it was deleted from that section. The cells don't get flushed back to init state when they go in to that queue.

As the code resets that cell for it's new home it's not telling the cell to do anything about the detail text. So it doesn't, and you end up with the delete detail text still there.

larswik
Aug 16, 2012, 04:28 AM
So what is the right approach? Do I try and delete the detailedTextLable in some way or try to delete it from the NSIndex array to remove the cell completely?

It seems that even thought I delete it from the tableview it is not deleted / removed from the index.

Or is the answer to use a 'Multiple Reuse Identifier' when creating the array?

MattInOz
Aug 16, 2012, 04:57 AM
You could try deliberately setting detailTextLabel.text to Nil when you don't want it to show anything. Could do the trick and avoid needing to have multiple ID's.

Reason077
Aug 16, 2012, 10:13 AM
So what is the right approach? Do I try and delete the detailedTextLable in some way or try to delete it from the NSIndex array to remove the cell completely?

It seems that even thought I delete it from the tableview it is not deleted / removed from the index.

Or is the answer to use a 'Multiple Reuse Identifier' when creating the array?

Your table has two types of cells. One type with a subtitle (UITableViewCellStyleSubtitle) and one without (UITableViewCellStyleDefault).

The problem is that you are using the same reuse identifier for both types.

You should use a different identifier for each type (e.g. "Basic-Cell" and "Subtitle-Cell"), and call dequeueReusableCellWithIdentifier with the correct identifier depending on which type of cell you need.

dejo
Aug 16, 2012, 10:32 AM
if (tableView == battleTableView) {

Is your tableViewController delegate to more than one tableView? The above line of code seems to indicate that.

larswik
Aug 16, 2012, 02:18 PM
Dejo - Yes I have 2 tableviews.

Reason077 - I see what you are saying so it would look something like this...

static NSString *CellIdentifier_Combat = @"combatCell";
static NSString *CellIdentifier_Standard = @"standardCell";

UITableViewCell *cell_combat = [tableView dequeueReusableCellWithIdentifier:CellIdentifier_Combat];

UITableViewCell *cell_standard = [tableView dequeueReusableCellWithIdentifier:CellIdentifier_Standard];

if (tableView == battleTableView) {
if(indexPath.section == 0){
if (cell_combat == nil) {
cell_combat = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

}
else{
cell_standard = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }

}





This would allow for 2 different storage locations for cells?

larswik
Aug 16, 2012, 03:04 PM
I tested the code out and it works! I left one of the UITablviewCells called 'cell' so I didn't have to alter all the code. Then I just created a new one combat_cell. It crashed when I first tried it and it turned out to be that I needed to 'return cell' or 'return combat_cell'. Once that happened it worked as expected.

Thanks for helping me diagnose the problem!

Reason077
Aug 16, 2012, 04:36 PM
static NSString *CellIdentifier_Combat = @"combatCell";
static NSString *CellIdentifier_Standard = @"standardCell";

UITableViewCell *cell_combat = [tableView dequeueReusableCellWithIdentifier:CellIdentifier_Combat];

UITableViewCell *cell_standard = [tableView dequeueReusableCellWithIdentifier:CellIdentifier_Standard];

if (tableView == battleTableView) {
if(indexPath.section == 0){
if (cell_combat == nil) {
cell_combat = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

}
else{
cell_standard = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }

}





While this will work, it's not ideal because you're de-queuing 2 cells but then only using one of them. That means that new cells will be getting alloc'ed all the time, which is slow.

A better version might be something like:

NSString *cellIdentifier;

if (tableView == battleTableView)
cellIdentifier = @"CombatCell";
else
cellIdentifier = @"StandardCell";

UITableViewCell *cell_combat = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

larswik
Aug 16, 2012, 04:52 PM
I see what you are saying. I did think of that but then said even though 2 get allocated and only one gets used it is destroyed when the Method ends. I didn't think it would cause a slow down but I do see what you are saying.

Thanks for that. I will add that that to it.