Objective C: Sending arguments to a method called by a UIButton

15,471

Solution 1

You can't - UIControl action selectors are invoked with no parameters, the control that is the source of the action, or the control that is the source of the action and the UIEvent which occurred on that control. In IB you have to connect the UIButton to such a method: you can't add any other custom parameters.

If you want it to have access to other objects, they need to be instance variables.

Review Apple's Introduction to Objective C if you want to understand how to define instance variables.

Solution 2

You could take the approach where you extend UIButton.

@interface MyButton : UIButton
@property (nonatomic, retain) NSDictionary *userInfo;
@end

Then your method

- (void)foo:(MyButton *)sender{
    NSLog(@"%@", [sender.userInfo valueForKeyPath:@"extraData"]);
}

And to set userInfo

...
MyButton *myButton = (MyButton *)[UIButton buttonWithType:UIButtonTypeCustom];
//set up a dictionary with info, called userInfo
myButton.userInfo = userInfo;
[myButton addTarget:self selector:@selector(foo:) forControlEvent:UIControlEventTouchUpInside];

Would that work for you?

Share:
15,471
Chris
Author by

Chris

Updated on June 04, 2022

Comments

  • Chris
    Chris about 2 years

    I have a method that is being called when a UIButton is clicked. When I create the button I want it to store an NSTimer as an argument.

    This is the timer and the creation of the UIButton. How would I add in the timer to be sent down to the method? I've tried withObject:timer but it gives me a warning and crashes at runtime.

    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:(0.009) target:self selector:@selector(moveStickFig:) userInfo:stickFig repeats:YES];
    [stickFig addTarget:self action:@selector(tapFig:andTime:) forControlEvents:UIControlEventTouchUpInside];
    

    This is the method I'm sending it down to:

    -(void) tapFig:(id)sender andTime:(NSTimer *)timer
    

    I've also tried [stickFig performSelector:@selector(tapFig:andTime) withObject:nil withObject:timer] after I defined the UIButton, but that also results in a warning and crashes.

  • Chris
    Chris over 13 years
    How would I make the timer an instance variable that I can use in other methods?
  • Phil Willoughby
    Phil Willoughby over 13 years
    Doesn't work - you don't get to pick the parameter send by a UIControl action; it's always the control.
  • lomanf
    lomanf over 13 years
    Oh, I suggest the "support class" because I meant you do not have just one instance of the NSTimer.. I supposed you have multiple buttons and multiple timers. Otherwise, a simple instance property of your ViewController is enought. Bye.
  • user102008
    user102008 about 13 years
    "it should be retained by the UIButton when you add the target" This is not true. Your solution won't work.
  • user102008
    user102008 about 13 years
    Your "timer" in "viewDidLoad" is a local variable. setting it accomplishes nothing. it does not set the instance variable
  • user102008
    user102008 about 13 years
    and where on earth would the first method get these array elements from? if the first method had the arguments somehow to begin with (that's the whole point of this question) then it wouldn't need the second method
  • lomanf
    lomanf about 13 years
    Thank you. That's true, the target is NOT retained and it should be retained for example in a property. BTW, this doesn't mean that the purpose of the solution won't work. The scope of the solution was to delegate the logic and multiple parameters of a complex button action to someone else. In this case, he just need to reach the NSTimer then the cost/benefit of a whole delegation is not really useful but I think that the logic is still valid.
  • Admin
    Admin about 13 years
    There are actually three possible signatures with zero, one, or two parameters for action methods.
  • user102008
    user102008 about 13 years
    if you are going to retain the delegate as a property in self, you might as well just retain the timer itself as a property of self, and not bother with creating this extra class and all. also, you still have the problem of not knowing when to release this property unless you know how long the button will be around
  • Moshe
    Moshe about 13 years
    @user102008 - Yikes! You're right. It's supposed to be sample code, but I've modified it.
  • lomanf
    lomanf about 13 years
    As I told, this is an approach and was intended to add more "stuff" into the delegate (like the NSTimer and more stuff). The button is part of the controller, you can keep both the button and the delegate alive until the functionality is needed. Set the NSTimer as property was quite obvious and already answered. I wanted to try to put another point of view. Anyway, thanks for your clever support.