Resolved UITableView Problem

Discussion in 'iPhone/iPad Programming' started by larswik, Aug 15, 2012.

  1. larswik, Aug 15, 2012
    Last edited: Aug 16, 2012

    macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    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?

    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"Cell";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        
        if (cell == nil) {
            [COLOR="Red"]cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];[/COLOR]
            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"]];
                
                [COLOR="Red"]cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];[/COLOR]
                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"]) {
                   [COLOR="Red"] cell.detailTextLabel.textColor = [UIColor redColor];[/COLOR]
                }
                else{
                   [COLOR="Red"] cell.detailTextLabel.textColor = [UIColor blackColor];[/COLOR]
                }
                
            }
        }
            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;
    }
    
    
     

    Attached Files:

  2. macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #2
    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.
     
  3. thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #3
    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?
     
  4. macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #4
    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.
     
  5. macrumors 68000

    Reason077

    Joined:
    Aug 14, 2007
    #5
    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.
     
  6. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #6
    Is your tableViewController delegate to more than one tableView? The above line of code seems to indicate that.
     
  7. thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #7
    Dejo - Yes I have 2 tableviews.

    Reason077 - I see what you are saying so it would look something like this...
    Code:
    static NSString *[COLOR="Red"]CellIdentifier_Combat[/COLOR] = @"combatCell";
    static NSString *CellIdentifier_Standard = @"standardCell";
    
    UITableViewCell *cell_combat = [tableView dequeueReusableCellWithIdentifier:[COLOR="Red"]CellIdentifier_Combat[/COLOR]];
    
    UITableViewCell *cell_standard = [tableView dequeueReusableCellWithIdentifier:CellIdentifier_Standard];
    
    if (tableView == battleTableView) {
        if(indexPath.section == 0){
            if ([COLOR="Red"]cell_combat[/COLOR] == nil) {
                [COLOR="Red"]cell_combat[/COLOR] = [[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?
     
  8. thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #8
    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!
     
  9. macrumors 68000

    Reason077

    Joined:
    Aug 14, 2007
    #9
    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:

    Code:
    NSString *cellIdentifier;
    
    if (tableView == battleTableView)
      cellIdentifier = @"CombatCell";
    else
      cellIdentifier = @"StandardCell";
    
    UITableViewCell *cell_combat = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
     
  10. thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #10
    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.
     

Share This Page