Question

Is there a way to get a reference to the view controller of my superview? There were several instances that I needed this on the past couple of months, but didn't know how to do it. I mean, if I have a custom button on a custom cell, and I wish to get a reference of the table view controller that controls the cell I`m currently in, is there a code snippet for that? Or is it something that I should just solve it by using better design patterns?

Thanks!

Was it helpful?

Solution 2

When I asked this question I was thinking of, in a situation where I have custom cells with buttons on them, how can the TableViewController know which cell's button was tapped. More recently, reading the book "iOS Recipes", I got the solution:

-(IBAction)cellButtonTapped:(id)sender
{
NSLog(@"%s", __FUNCTION__);
UIButton *button = sender;

//Convert the tapped point to the tableView coordinate system
CGPoint correctedPoint = [button convertPoint:button.bounds.origin toView:self.tableView];

//Get the cell at that point
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:correctedPoint];

NSLog(@"Button tapped in row %d", indexPath.row);
}

Another solution, a bit more fragile (though simpler) would be:

- (IBAction)cellButtonTapped:(id)sender 
{
    // Go get the enclosing cell manually
    UITableViewCell *parentCell = [[sender superview] superview];
    NSIndexPath *pathForButton = [self.tableView indexPathForCell:parentCell];
}

And the most reusable one would be to add this method to a category of UITableView

- (NSIndexPath *)prp_indexPathForRowContainingView:(UIView *)view 
{
   CGPoint correctedPoint = [view convertPoint:view.bounds.origin toView:self]; 
   return [self indexPathForRowAtPoint:correctedPoint];
}

And then, on your UITableViewController class, just use this:

- (IBAction)cellButtonTapped:(id)sender 
{
    NSIndexPath *pathForButton = [self.tableView indexPathForRowContainingView:sender];
}

OTHER TIPS

Your button should preferably not know about its superviews view controller.

However, if your button really needs to message objects that it shouldn't know the details about, you can use delegation to send the messages you want to the buttons delegate.

Create a MyButtonDelegate protocol and define the methods that everyone that conforms to that protocol need to implement (the callback). You can have optional methods as well.

Then add a property on the button @property (weak) id<MyButtonDelegate> so that any class of any kind can be set as the delegate as long as it conforms to your protocol.

Now the view controller can implement the MyButtonDelegate protocol and set itself as the delegate. The parts of the code that require knowledge about the view controller should be implemented in the delegate method (or methods).

The view can now send the protocol messages to its delegate (without knowing who or what it is) and the delegate can to the appropriate thing for that button. This way the same button could be reused because it doesn't depend on where it is used.

If you know which class is the superview of your view controller, you can just iterate through the subviews array and typecheck for your superclass.

eg.

UIView *view; 

for(tempView in self.subviews) {

   if([tempView isKindOfClass:[SuperViewController class] ])

        {
           // you got the reference, do waht you want

         }


   }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top