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