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!!
- (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;
}
Just wanted to put an update on this post. I spent 12 hours yesterday trying to fix this and it's just beyond my current skills. I set the cell selection style to none, which sucks but it's time to throw in the towel for now.
I completely ditched that code in favor of the following approach, which checked all currently visible index paths for the presence of an index path assigned to a sound and then removed subviews as appropriate:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/* NSArray *allVisibleCells = [table visibleCells];
leftIsVisible = FALSE;
downIsVisible = FALSE;
rightIsVisible = FALSE;
NSLog(@"\n\n\n", (leftIsVisible ? @"TRUE" : @"FALSE"));
NSLog(@"Start: %@\n", (leftIsVisible ? @"TRUE" : @"FALSE"));
for (UITableViewCell *visibleCell in allVisibleCells){
NSIndexPath *visibleCellIndexPath = [table indexPathForCell: visibleCell];
NSLog(@"visible cell index path %@\n", visibleCellIndexPath);
if ([visibleCellIndexPath compare: leftOldIndexPath] == NSOrderedSame) {
leftIsVisible = TRUE;
NSLog(@"Compare successful: %@\n", (leftIsVisible ? @"TRUE" : @"FALSE"));
}
if ([visibleCellIndexPath compare: downOldIndexPath] == NSOrderedSame) {
downIsVisible = TRUE;
}
if ([visibleCellIndexPath compare: rightOldIndexPath] == NSOrderedSame){
rightIsVisible = TRUE;
}
}
NSLog(@"After the first fast enumeration: %@\n", (leftIsVisible ? @"TRUE" : @"FALSE"));
NSLog(@"After check for left is still visible %@\n", (leftIsVisible ? @"TRUE" : @"FALSE"));
if(leftIsVisible == FALSE){
[selectedSoundLeft removeFromSuperview];
[selectedSoundLeftAndDown removeFromSuperview];
[selectedSoundLeftAndRight removeFromSuperview];
[selectedSoundLeftAndDownAndRight removeFromSuperview];
}
if(downIsVisible == FALSE){
[selectedSoundDownAndRight removeFromSuperview];
[selectedSoundDown removeFromSuperview];
}
if (rightIsVisible == FALSE){
[selectedSoundRight removeFromSuperview];
} */