UITableViewCell selected subview ghosts

Posted by Jonathan Cohen on Stack Overflow See other posts from Stack Overflow or by Jonathan Cohen
Published on 2010-04-02T13:58:25Z Indexed on 2010/04/02 14:03 UTC
Read the original article Hit count: 801

Hi all,

I'm learning about the iPhone SDK and have an interesting exception with UITableViewCell subview management when a finger is pressed on some rows.

The table is used to assign sounds to hand gestures -- swiping the phone in one of 3 directions triggers the sound to play. Selecting a row displays an action sheet with 4 options for sound assignment: left, down, right, and cancel. Sounds can be mapped to one, two, or three directions so any cell can have one of seven states: left, down, right, left and down, left and right, down and right, or left down and right. If a row is mapped to any of these seven states, a corresponding arrow or arrows are displayed within the bounds of the row as a subview. Arrows come and go as they should in a given screen and when scrolling around.

However, after scrolling to a new batch of rows, only when I press my finger down on some (but not all) rows, does an arrow magically appear in the selected state background. When I lift my finger off the row, and the action sheet appears, the arrow disappears. After pressing any of the four buttons, I can't replicate this anymore. But it's really disorienting and confusing to see this arrow flash on screen because the selected row isn't assigned to anything.

What haven't I thought to look into here? All my table code is pasted below and this is a screencast of the problem: http://www.screencast.com/users/JonathanGCohen/folders/Jing/media/d483fe31-05b5-4c24-ab4d-70de4ff3a0bf

Am I managing my subviews wrong or is there a selected state property I'm missing? Something else? Should I have included any more information in this post to make things clearer? Thank you!!

#pragma mark -
#pragma mark Table

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return ([categories count] > 0) ? [categories count] : 1;
}

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section {
    if ([categories count] == 0)
        return 0;
    NSMutableString *key = [categories objectAtIndex:section];
    NSMutableArray *nameSection = [categoriesSounds objectForKey:key]; 
    return [nameSection count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
    NSString *key = [categories objectAtIndex:section];
    NSArray *nameSection  = [categoriesSounds objectForKey:key];
    static NSString *SectionsTableIdentifier = @"SectionsTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
                             SectionsTableIdentifier];
    NSArray *sound = [categoriesSounds objectForKey:key];
    NSString *soundName = [[sound objectAtIndex: row] objectAtIndex: 0];
    NSString *soundOfType = [[sound objectAtIndex: row] objectAtIndex: 1];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:SectionsTableIdentifier] autorelease];
    }

    cell.textLabel.text = [[nameSection objectAtIndex:row] objectAtIndex: 0];

    NSUInteger soundSection = [[[sound objectAtIndex: row] objectAtIndex: 2] integerValue];
    NSUInteger soundRow = [[[sound objectAtIndex: row] objectAtIndex: 3] integerValue];

        NSUInteger leftRow = [leftOldIndexPath row];
        NSUInteger leftSection = [leftOldIndexPath section];
        if (soundRow == leftRow && soundSection == leftSection && leftOldIndexPath !=nil){
            [selectedSoundLeftAndDown removeFromSuperview];
            [selectedSoundLeftAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundLeft];
            selectedSoundLeft.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundLeft];
        }

        NSUInteger downRow = [downOldIndexPath row];
        NSUInteger downSection = [downOldIndexPath section];
        if (soundRow == downRow && soundSection == downSection && downOldIndexPath !=nil){
            [selectedSoundLeftAndDown removeFromSuperview];
            [selectedSoundDownAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundDown];
            selectedSoundDown.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundDown];
        }

        NSUInteger rightRow = [rightOldIndexPath row];
        NSUInteger rightSection = [rightOldIndexPath section];
        if (soundRow == rightRow && soundSection == rightSection && rightOldIndexPath !=nil){
            [selectedSoundDownAndRight removeFromSuperview];
            [selectedSoundLeftAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundRight];
            selectedSoundRight.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundRight];
        }

        // combos
        if (soundRow == leftRow && soundRow == downRow &&
            soundSection == leftSection && soundSection == downSection){
            [selectedSoundLeft removeFromSuperview];
            [selectedSoundDown removeFromSuperview];
            [selectedSoundLeftAndDownAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundLeftAndDown];
            selectedSoundLeftAndDown.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundLeftAndDown];
        }
        if (soundRow == leftRow && soundRow == rightRow &&
            soundSection == leftSection && soundSection == rightSection){
            [selectedSoundLeft removeFromSuperview];
            [selectedSoundRight removeFromSuperview];
            [selectedSoundLeftAndDownAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundLeftAndRight];
            selectedSoundLeftAndRight.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundLeftAndRight];
        }
        if (soundRow == downRow && soundRow == rightRow &&
            soundSection == downSection && soundSection == rightSection){
            [selectedSoundDown removeFromSuperview];
            [selectedSoundRight removeFromSuperview];
            [selectedSoundLeftAndDownAndRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundDownAndRight];
            selectedSoundDownAndRight.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundDownAndRight];
        }
        if (soundRow == leftRow && soundRow == downRow && soundRow == rightRow &&
            soundSection == leftSection && soundSection == downSection && soundSection == rightSection){
            [selectedSoundLeftAndDown removeFromSuperview];
            [selectedSoundLeftAndRight removeFromSuperview];
            [selectedSoundDownAndRight removeFromSuperview];
            [selectedSoundLeft removeFromSuperview];
            [selectedSoundDown removeFromSuperview];
            [selectedSoundRight removeFromSuperview];
            [cell.contentView addSubview: selectedSoundLeftAndDownAndRight];
            selectedSoundLeftAndDownAndRight.frame = CGRectMake(200,8,30,30);
        }
        else {
            [cell.contentView sendSubviewToBack: selectedSoundLeftAndDownAndRight];
        }

    [indexPath retain];
    return cell;    
}

- (NSMutableString *)tableView:(UITableView *)tableView
       titleForHeaderInSection:(NSInteger)section {
    if ([categories count] == 0)
        return nil;
    NSMutableString *key = [categories objectAtIndex:section];
    if (key == UITableViewIndexSearch)
        return nil;
    return key;
}

- (NSMutableArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (isSearching)
        return nil;
    return categories;
}

- (NSIndexPath *)tableView:(UITableView *)tableView
  willSelectRowAtIndexPath:(NSIndexPath *)indexPath {   
    [table reloadData];
    [selectedSoundLeft removeFromSuperview];
    [selectedSoundDown removeFromSuperview];
    [selectedSoundRight removeFromSuperview];
    [selectedSoundLeftAndDown removeFromSuperview];
    [selectedSoundLeftAndRight removeFromSuperview];
    [selectedSoundDownAndRight removeFromSuperview];
    [selectedSoundLeftAndDownAndRight removeFromSuperview];

    [search resignFirstResponder];  
    if (isSearching == YES && [search.text length] != 0 ){
        searched = YES;
    } 

    search.text = @"";
    isSearching = NO;
    [tableView reloadData];
    [indexPath retain];
    [indexPath retain];
    return indexPath;
}

- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [table reloadData];

    selectedIndexPath = indexPath;

    [table reloadData];
    NSInteger section = [indexPath section];
    NSInteger row = [indexPath row];
    NSString *key = [categories objectAtIndex:section];
    NSArray *sound = [categoriesSounds objectForKey:key];
    NSString *soundName = [[sound objectAtIndex: row] objectAtIndex: 0];

    [indexPath retain];
    [indexPath retain];

    NSMutableString *title = [NSMutableString stringWithString: @"Assign Gesture for "];
    NSMutableString *soundFeedback = [NSMutableString stringWithString: (@"%@", soundName)];
    [title appendString: soundFeedback];        

    UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:(@"%@", title)
                                          delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          destructiveButtonTitle: nil
                                          otherButtonTitles:@"Left",@"Down",@"Right",nil];
    action.actionSheetStyle = UIActionSheetStyleDefault;
    [action showInView:self.view];
    [action release];
}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{

    NSInteger section = [selectedIndexPath section];
    NSInteger row = [selectedIndexPath row];
    NSString *key = [categories objectAtIndex:section];
    NSArray *sound = [categoriesSounds objectForKey:key];
    NSString *soundName = [[sound objectAtIndex: row] objectAtIndex: 0];
    NSString *soundOfType = [[sound objectAtIndex: row] objectAtIndex: 1];
    NSUInteger soundSection = [[[sound objectAtIndex: row] objectAtIndex: 2] integerValue];
    NSUInteger soundRow = [[[sound objectAtIndex: row] objectAtIndex: 3] integerValue];

    NSLog(@"sound row is %i", soundRow);
    NSLog(@"sound section is row is %i", soundSection);

    typedef enum {
        kLeftButton = 0,
        kDownButton,
        kRightButton,
        kCancelButton
    } gesture;  

    switch (buttonIndex) {


        //Left
        case kLeftButton:

            showLeft.text = soundName;
            left    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
            AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                        fileURLWithPath:left], &soundNegZ); 
            AudioServicesPlaySystemSound (soundNegZ); 

            [table deselectRowAtIndexPath:selectedIndexPath animated:YES];

            leftIndexSection = [NSNumber numberWithInteger:section];
            leftIndexRow = [NSNumber numberWithInteger:row];
            NSInteger leftSection = [leftIndexSection integerValue];
            NSInteger leftRow = [leftIndexRow integerValue];
            NSString  *leftKey = [categories objectAtIndex: leftSection];
            NSArray   *leftSound = [categoriesSounds objectForKey:leftKey];
            NSInteger leftSoundSection = [[[leftSound objectAtIndex: leftRow] objectAtIndex: 2] integerValue];
            NSInteger leftSoundRow = [[[leftSound objectAtIndex: leftRow] objectAtIndex: 3] integerValue];
            leftOldIndexPath = [NSIndexPath indexPathForRow:leftSoundRow inSection:leftSoundSection];           


            break;


        //Down
        case kDownButton:

            showDown.text = soundName;
            down    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
            AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                        fileURLWithPath:down], &soundNegX); 
            AudioServicesPlaySystemSound (soundNegX);

            [table deselectRowAtIndexPath:selectedIndexPath animated:YES];

            downIndexSection = [NSNumber numberWithInteger:section];
            downIndexRow = [NSNumber numberWithInteger:row];
            NSInteger downSection = [downIndexSection integerValue];
            NSInteger downRow = [downIndexRow integerValue];
            NSString  *downKey = [categories objectAtIndex: downSection];
            NSArray   *downSound = [categoriesSounds objectForKey:downKey];
            NSInteger downSoundSection = [[[downSound objectAtIndex: downRow] objectAtIndex: 2] integerValue];
            NSInteger downSoundRow = [[[downSound objectAtIndex: downRow] objectAtIndex: 3] integerValue];
            downOldIndexPath = [NSIndexPath indexPathForRow:downSoundRow inSection:downSoundSection];           


            break;



        //Right
        case kRightButton:

            showRight.text = soundName;
            right    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
            AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                        fileURLWithPath:right], &soundPosX);    
            AudioServicesPlaySystemSound (soundPosX);

            [table deselectRowAtIndexPath:selectedIndexPath animated:YES];

            rightIndexSection = [NSNumber numberWithInteger:section];
            rightIndexRow = [NSNumber numberWithInteger:row];
            NSInteger rightSection = [rightIndexSection integerValue];
            NSInteger rightRow = [rightIndexRow integerValue];
            NSString *rightKey = [categories objectAtIndex: rightSection];
            NSArray *rightSound = [categoriesSounds objectForKey:rightKey];
            NSInteger rightSoundSection = [[[rightSound objectAtIndex: rightRow] objectAtIndex: 2] integerValue];
            NSInteger rightSoundRow = [[[rightSound objectAtIndex: rightRow] objectAtIndex: 3] integerValue];
            rightOldIndexPath = [NSIndexPath indexPathForRow:rightSoundRow inSection:rightSoundSection];            
            break;


        case kCancelButton:
            [table deselectRowAtIndexPath:selectedIndexPath animated:YES];
            break;


        default:
            break;
    }

    UITableViewCell *viewCell = [table cellForRowAtIndexPath: selectedIndexPath];
    NSArray *subviews = viewCell.subviews;
    for (UIView *cellView in subviews){
        cellView.alpha = 1;
    }

    [table reloadData];

}


- (NSInteger)tableView:(UITableView *)tableView
sectionForSectionIndexTitle:(NSMutableString *)title
               atIndex:(NSInteger)index {
    NSMutableString *category = [categories objectAtIndex:index];
    if (category == UITableViewIndexSearch) {
        [tableView setContentOffset:CGPointZero animated:NO];
        return NSNotFound;
    }
    else return index;
}

© Stack Overflow or respective owner

Related posts about iphone

Related posts about uitableview