John Parker
John Parker

Reputation: 54445

Identifying UISegmentedControl embedded in custom UITableViewCell when calling selector

I've a custom UITableViewCell which has a UISegmentedControl added as a subview via the cell's contentView property as follows:

#define TABLECELL_SEGMENT_TAG 1

...


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

    UISegmentedControl *testSegmentedControl;

    // Check for a reusable cell first, use that if it exists
    UITableViewCell *tableCell = [tableView dequeueReusableCellWithIdentifier:@"OurCustomCell"];

    // If there is no reusable cell of this type, create a new one
    if (!tableCell) {
        tableCell = [[[UITableViewCell alloc] 
                      initWithStyle:UITableViewCellStyleSubtitle
                      reuseIdentifier:@"OurCustomCell"] autorelease];


        // Create our segmented control
        NSArray *segmentItems = [NSArray arrayWithObjects:@"Option 1", @"Option 2", nil];
        UISegmentedControl *testSegmentedControl = [[UISegmentedControl alloc] initWithItems:segmentItems];
        [testSegmentedControl setTag:TABLECELL_SEGMENT_TAG];
        [[tableCell contentView] addSubview:testSegmentedControl];
        [testSegmentedControl release];
    }

    // Set the selected segment status as required
    testSegmentedControl = (UISegmentedControl *)[tableCell.contentView viewWithTag:TABLECELL_SEGMENT_TAG];

    ...

    [testSegmentedControl addTarget:self
                         action:@selector(segmentedControlUpdated:)
               forControlEvents:UIControlEventValueChanged];        

    return tableCell;
}

What I need to be able to do is somewhat set the addTarget selector for each segmented control so that it identifies the row in question, an obvious solution being to use the segmented control's tag. However as you can see I'm already using the tag to retrieve the control from within the custom cell's contentView if an existing cell is returned via the UITableView's dequeueReusableCellWithIdentifier: method.

As such, I'm just wondering what the best way to achieve this? (I presume I could simply extend the UISegmentedControl class to add an associatedTableRow property, but I'm wondering if there's a more elegant solution.)

Upvotes: 1

Views: 4363

Answers (2)

Matthias Bauch
Matthias Bauch

Reputation: 90117

Because subclassing is always the worst choice I would do the superview superview dance.

- (IBAction)controlChanged:(UIControl *)sender
    NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
    // do something
}

since iOS7 changed the view hierarchy the above code won't work. You will need to use indexPathForRowAtPoint::

- (IBAction)controlChanged:(UIControl *)sender {
    CGPoint senderOriginInTableView = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:senderOriginInTableView];
    // do something
}

Upvotes: 5

Hollance
Hollance

Reputation: 2976

Make a subclass of UITableViewCell that has a reference to the UISegmentedControl as a property and instantiate that instead of UITableViewCell. Then you don't need the tag to refer to the segmented control and you can use it to hold the row number.

However, you could also put the row number in that subclass as a property, or even make the subclass handle the target-action. In any case, making a subclass gives you greater flexibility to handle this.

Upvotes: 4

Related Questions