1

I want to place a button in each cell of a table. I want the target to be a class that I'm using to handle all of the API calls. I want the button's method to be in the friendController class, not in the UITableView's View Controller.

[cell.deleteButton addTarget:friendController 
action:@selector(deleteFriend: forID:cell.idNumber) 
forControlEvents:UIControlEventTouchUpInside];

Where friendController is the class with the API calls, and cell.idNumber is an instance variable of each cell containing the ID number of the user associated with that cell.

I know (well, I presume) that I could set the cell itself as the target and then have a method which looks like:

-(IBAction)deleteFriend:(id)sender {
    [friendController deleteFriend:self.idNumber];
}

Is that correct? It doesn't seem like an elegant way of doing this. Is there a way to do it the way I want to, or is there a better way to do it?

EDIT: I emboldened the last crucial part of my question. I want the button's action to be a method in another class (friendController). friendController is a class I created to house all of the API calls and business logic. If I set the target to friendController, must the action be a method in that class?

Rory Byrne
  • 923
  • 1
  • 12
  • 22
  • take a look this link http://stackoverflow.com/questions/3716633/passing-parameters-on-button-actionselector – Matrosov Oleksandr Apr 19 '14 at 00:07
  • You could try subclassing UIButton and creating a property for `idNumber` which you can later access in your `deleteFriend:` method. – sooper Apr 19 '14 at 00:08
  • So, I should sub-class my button and add a parameter to store the idNumber? And then I can use `sender.idNumber` to get access to it in the button's action method? I didn't see your reply before I commented, @sooper. Thanks, all the same. – Rory Byrne Apr 19 '14 at 00:09

4 Answers4

3

You can do this two ways.

Subclassing UIButton

The first would be to subclass UIButton and create a property for the idNumber. So you would first set the property like so:

cell.deleteButton.idNumber = /* set id here */
[cell.deleteButton addTarget:friendController 
action:@selector(deleteFriend:) 
forControlEvents:UIControlEventTouchUpInside];

and then access it inside your deleteFriend: method:

- (IBAction)deleteFriend:(id)sender {
    YourButtonClass *button = (YourButtonClass *)sender;
    [friendController deleteFriend:button.idNumber];
}

Retrieve the idNumber directly from the cell

Described in this post you can grab the index path of the button's cell and then access the idNumber from there.

Community
  • 1
  • 1
sooper
  • 5,991
  • 6
  • 40
  • 65
  • Sorry for repeating this question, but am I right in saying that the deleteFriend method must be in the Table View Controller where I instantiate all of the cells? I wanted to set the target to friendController so I could link the button with a method in that class. Am I misunderstanding the purpose of addTarget? My goal was to avoid creating a method that simply calls another method. – Rory Byrne Apr 19 '14 at 00:23
  • `deleteFriend` doesn't have to be in the table view controller. If it belongs to `friendController` then it will be called there as you've set the target accordingly. – sooper Apr 19 '14 at 00:29
  • Not much value-add for a button subclass here. The superclass contains a tag. – danh Apr 19 '14 at 00:49
0

With 2 parameters indicating the control that sends the message and the event that triggered the message:

action:@selector(buttonAction:Second:)

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btn addTarget:self action:@selector(buttonAction:Second:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)buttonAction:(NSString *)firstCharacter
              Second:(NSNumber *)second
{

}
Erhan
  • 908
  • 8
  • 19
0

Use the tag property of the button.

cell.deleteButton.tag = cell.idNumber;
[cell.deleteButton addTarget:friendController action:@selector(deleteFriend:) forControlEvents:UIControlEventTouchUpInside];

In the method, you can use the tag to retrieve the cell idNumber

-(IBAction)deleteFriend:(id)sender {
     int idNumber = ((UIButton *) sender).tag;
     [friendController deleteFriend: idNumber];
} 
nprd
  • 1,942
  • 1
  • 13
  • 16
  • Is this considered elegant? Would it be better practice to sub-class the button and add a dedicated property for the idNumber? – Rory Byrne Apr 19 '14 at 00:12
  • Also, does my `deleteFriend` method need to be in the View Controller where I instantiate each cell? If I set the target of the button to be an arbitrary class, can the action be a method of that class? – Rory Byrne Apr 19 '14 at 00:19
  • This seems like a fine place to use the tag variable rather than subclassing, but subclassing is a more general solution if you need to store more than an integer. There are other ways as well - Obj-C associated objects, for example. The method that gets called will get called in whatever object you set as the target. It does not have to be the viewController. – EricS Apr 19 '14 at 01:16
  • the tag property is used for tagging some value to the button. If multiple buttons are calling the same selector then the differentiation can be established by tags. Tag is to attach some info the the view that you can differentiate it easily. As per the documentation "Tag is an integer that you can use to identify view objects in your application. The default value is 0. You can set the value of this tag and use that value to identify the view later." – nprd Apr 19 '14 at 03:40
0

Since the button is inside a UITableViewCell, you might consider subclass a UITableViewCell with your property idNumber(I don't like reuse Tag because it can only be an integer) and a delegate:

    @protocol MyTableViewCellDelegate;

@interface MyTableViewCell : UITableViewCell

@property (nonatomic, assign) NSInteger idNumber;

@property (nonatomic, weak) id<MyTableViewCellDelegate> delegate;

@end

@protocol MyTableViewCellDelegate <NSObject>

-(void) shouldDeleteFriendById:(NSInteger)idNumber;

@end

And handle the button action inside the MyTableViewCell implementation:

- (void) myInit
{
    UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    [button addTarget:self action:@selector(onButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

    [self addSubview:button];
}

- (IBAction)onButtonClicked:(id)sender
{
    [self.delegate shouldDeleteFriendById:self.idNumber];
}

Then implement cell's delegate in your tableViewController:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCell *cell = (MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath];

    // Configure the cell...
    cell.idNumber = indexPath.row;
    cell.delegate = self;

    return cell;
}

- (void) shouldDeleteFriendById:(NSInteger)idNumber
{
    NSLog(@"should delete by id:%d", idNumber);
}
dichen
  • 1,643
  • 14
  • 19