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;
}