IkegawaTaro
IkegawaTaro

Reputation: 3563

When tapping an already selected cell in a UITableView, willSelectCellAtIndexPath gets called

I have a UITableView with two sections. Based on user interactions (selections and deselections), my datasource and UITableView are updated to move data between sections. Initially their is only data in section 0. When I tap a cell, willSelectCellAtIndexPath and didSelectCellAtIndexPath get called. As expected, when I tap the same cell again, didDeselectCellAtIndexPath is called.

Even after I begin to move data down to section 1 and select and deselect, the UITableView's delegate methods are called appropriately.

Once all data has been moved to Section 1, the UITableView begins to exhibit strange behavior. I can initially select a call and didSelectCellAtIndexPath is called. However, when I tap it again, didDeselectCellAtIndexPath is never called. Instead, any taps on the selected cell (I have confirmed it is indeed selected through [tableView indexPathsForSelectedCells] or any other cells in Section 1 only result in willSelectIndexPath and didSelectIndexPath getting called.

I have quite a bit of code in these delegate methods which is unrelated (I believe).... I do not explicitly change the selected state of a cell anywhere. I have posted willSelect method and can post more if necessary.

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (remainingItemIsSelected && indexPath.section == 0) {
        //other cells in the remaining items section are selected and a cell from that section is being selected

        NSMutableIndexSet *arrayIndexesToBeDeleted = [[NSMutableIndexSet alloc] init];
        for (NSIndexPath *previouslySelectedIndexPath in [tableView indexPathsForSelectedRows]) {
            if (((ReceiptItem *)[self.remainingReceiptItems objectAtIndex:previouslySelectedIndexPath.row]).allocated == YES) {

                //update data sources
                NSLog(@"%@%i%@,%i",@"Section #:",previouslySelectedIndexPath.section,@" Row #:",previouslySelectedIndexPath.row);
                [self.assignedReceiptItems addObject:[self.remainingReceiptItems objectAtIndex:previouslySelectedIndexPath.row]];
                [arrayIndexesToBeDeleted addIndex:previouslySelectedIndexPath.row];

                //update index path arrays
                [self.receiptItemsToDeleteIndexPaths addObject:previouslySelectedIndexPath];
                [self.receiptItemsToAddIndexPaths addObject:[NSIndexPath indexPathForRow:self.assignedReceiptItems.count-1 inSection:1]];

                //update the pressed indexpath to equal to resulting indexpath to pass on to the didSelect method
                if (previouslySelectedIndexPath.row < indexPath.row) {
                    indexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:0];
                }
            }
        }
        //Delete assigned items from the remaining receipt items
        [self.remainingReceiptItems removeObjectsAtIndexes:arrayIndexesToBeDeleted];
        //update table (move allocated item down)
        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:self.receiptItemsToDeleteIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView insertRowsAtIndexPaths:self.receiptItemsToAddIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView endUpdates];
        if (self.remainingReceiptItems.count == 0) {
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
        //other cells in the remaining items section are selected and a cell from assigned items is being selected
        return nil;
    }
    return indexPath;
}

Upvotes: 3

Views: 1989

Answers (1)

Mundi
Mundi

Reputation: 80273

From the Documentation for UITableViewDelegate:

tableView:willDeselectRowAtIndexPath:
This method is only called if there is an existing selection when the user tries to select a different row. The delegate is sent this method for the previously selected row.

If you think this through you will find that what you encounter is expected behavior. Tapping a row that is selected does not call will/didDeselctRowAtIndexPath on this row.

Instead, you could handle this in didSelectRowAtIndexPath for the selected row, i.e. deselect it there.

Possible Alternative

That being said, I think you are abusing the UITableView class. It is really not designed to do this moving stuff. You have no doubt noticed yourself that you have to write a lot of code to make this work -- the very reason you are encountering intractable errors.

It seems to me that a much cleaner (and ultimately more flexible) solution would be to have two separate table (or other) views that notify each other via delegates about datasource changes. Maybe a bit more work setting it up, but surely much less trouble down the road.

Upvotes: 1

Related Questions