I am trying to add a button to a view programmatically and i am using the following code:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Click Me" forState:UIControlStateNormal];
[button addTarget:self action:#selector(click:) forControlEvents:UIControlEventTouchDown];
[button setFrame:CGRectMake(50, 20, 80, 70)];
[self addButton:button];
according to me code looks right but i am getting error "Unknown action click"
addbutton and click is the method of the same class
and i am adding the buttons in my constructor
what's the problem with the click method? is there any syntax error!
Your problem is that you have a method named click but your are telling your button that the method is named click:. Notice the difference (the colon).
Change the #selector to #seletor(click) so it matches the actual method name.
Another option is to leave the #selector as-is but update your click method to click::
- (void)click:(UIButton *)button {
// button was tapped - do something
}
A sample how to add a action to a button ....
UIButton *button = [UIButton buttonWithTypeRoundRect];
[button addTarget:self action:#selector(myMethod) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(10,10,100,50);
//Do some more Configuration of the button like title.. Look at UIButton Class Reference
[self.view addSubview:button];
SomeTimes you see a small colon(:) after the method name in the selector something like this #selector(myMethod:)
which means this method takes some argument. the colon plays no role in the name of the method. if you are not sending any argument to the function then don't put colon after the name of the function.....
In addtarget option you can see that self is specified because self contains myMethod function. Here you are supposed to specify the reference of that object which contains your Method.
change
- (void)click:(id)sender{ NSLog(#"Button Clicked"); }
or change action click: to click
[button addTarget:self action:#selector(click) forControlEvents:UIControlEventTouchUpInside];
hi just simply try this -(void)click { // do what ever } i.e just remove colon in #selector(click:) hope it will work
Related
I would like to add targets to UIButtons by dynamically generating the selector names for the buttons as I iterate through a for loop. So far, I have an NSArray of 3 UIButtons:
NSArray *buttonArray = #[email, webPage, textMessage];
I would like now to do something like:
for(UIButton *button in buttonArray){
[button addTarget:self action:#selector(CUSTOM NAME HERE) forControlEvents:UIControlEventTouchUpInside];
}
It would be nice if I could dynamically form a custom name based on the name of the button (for example the name of the selector would be the button name + "ButtonProc", but I could also use an NSArray containing strings correlating to the selector names. How can I do something like this?
Use NSSelectorFromString().
for(UIButton *button in buttonArray){
[button addTarget:self action:NSSelectorFromString(CUSTOM NAME HERE) forControlEvents:UIControlEventTouchUpInside];
}
Don't forget to add : at the end of your selector string if your #IBAction is declared with the sender argument.
I add UIButton programmatically (self.button is my property UIButton):
self.button = [[UIButton alloc] initWithFrame:CGRectMake(139, 366, 42, 34)];
[self.button addTarget:self action:#selector(buttonPressed:completion:) forControlEvents:UIControlEventTouchUpInside];
I call programmatically to the button target and also I want the framework to invoke the target when the user push the button.
The target selector is:
-(void)buttonPressed:(UIButton*)sender completion:(void (^)())completionBlock;
The second argument is a block.
When I try to introspection/invoke the block I get an exception EXC_BAD_ACCESS (code=2, address=0x0)
I know that I try to invoke UITouchesEvent because of the framework target action.
How can I make custom target with completion block?
You can't pass a completion block there, but you can make something like this:
self.button = [[UIButton alloc] initWithFrame:CGRectMake(139, 366, 42, 34)];
[self.button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
-(void)buttonPressed:(UIButton*)sender {
[self buttonPressed:sender completion:^{
//something
}];
}
-(void)buttonPressed:(UIButton*)sender completion:(void (^)())completionBlock {
//do something
//invoke block
completionBlock();
}
You can't. For the button action, system expect to have a single parameter and that too is the sender(Invoker of the action method) ie the UIButton instance itself. If you want to do anything with a second argument i would suggest you to have a wrapper some thing like
-(void)buttonPressed:(UIButton*)sender
{
[self customMethodWithcompletion:^{
}];
}
Inside the customMethodWithcompletion you can perform your operations.
A target-action listener for UIKit must have one of the following three signatures:
- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event
If there is a first parameter, the "sender" control (the control that you are listening to actions for) will be passed to it. If there is furthermore a second parameter, the UIEvent object will be passed to it. You don't have any control over what is passed to the method.
There are many third-party libraries that implement a Block-based API for UIControls that you can find on the Internet. Essentially what they do is attach the completion block as an associative object to the control, and retrieve it in the handling method.
This button is declared in my base class:
{
// Setup done button for tool bar
UIButton *doneButton = [[UIButton alloc] initWithFrame:CGRectMake(170, 3, 110, 38)];
[doneButton setBackgroundColor:[UIColor blackColor]];
[doneButton setTitle:#"Done" forState:UIControlStateNormal];
[doneButton addTarget:_thisController action:#selector(doneButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
return doneButton;
}
Notice this line:
[doneButton addTarget:_thisController action:#selector(doneButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
The "doneButtonTapped:" method is only used in each sub class of my base class and never in the base class itself.
To avoid a warning in the base class I have to at least define the method:
- (void)doneButtonTapped:(id)sender {
}
Question:
Is there a way to avoid declaring the empty method and not get warnings?
Are blank methods like above a problem?
I know I could addTarget for the selector in each of the sub classes but there are quite a few of them. I just thought leaving everything in the doneButtonTapped method would be easier.
There is a way ;) :
NSString *stringMethod = #"doneButtonTapped:";
[doneButton addTarget:self action:NSSelectorFromString(stringMethod) forControlEvents:UIControlEventTouchUpInside];
In this way you can also change your method at runtime before create the button, just changing the string. And the warning so, are not shown in pre-compile time.
So, enjoy! ;)
I want be signaled when user will touch button (UIControlEventTouchUpInside). How do I add observer to UIButton?
Look at the documentation of UIControl.
[myButton addTarget:self
action:#selector(touch:)
forControlEvents:UIControlEventTouchUpInside];
This method works for anything that inherits from UIControl (including but not limited to UIButtons :)
// add target and action
[myButton addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
where the target is the class where the UIButton is added or implemented. If you set nil for addTarget, the action will go through the responder chain until a responder is found that responds to the buttonClicked: selector. buttonClicked: selector is implemented like the following:
-(void)buttonClicked:(id)sender
{
// do stuff here
}
How do I set a tag for a button programmatically?
I later want to compare to tags for a conclusion
I've tried this
-(IBAction)buttonPressed:(id)sender{
NSLog(#"%d", [sender tag]);
}
but that just crashes the app.
Any other ideas?
You need to cast sender as a UIButton:
-(IBAction)buttonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", [button tag]);
}
Edit: Regarding the message "unrecognized selector"...
Based on your error message, it's not able to call the buttonPressed method in the first place. Notice in the error message it is looking for "buttonPressed" (no colon at end) but the method is named "buttonPressed:". If you are setting the button target in code, make sure the selector is set to buttonPressed: instead of just buttonPressed. If you are setting the target in IB, the xib may be out of sync with the code.
Also, your original code "[sender tag]" should also work but to access button-specific properties, you'll still need to cast it to UIButton.
I know this is an old question and been answered many a time in other questions, but it came up in a google search as second from the top. So, here is the answer to why it was crashing. Change it to 'button.tag'
-(void)myMethod
{
UIButton *theButton = [UIButton buttonWithType:UIButtonTypeCustom];
[theButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
theButton.tag = i;//or whatever value you want. In my case it was in a forloop
}
-(void)buttonPressed:(id)sender
{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", button.tag);
}
No need for casting. This should work:
-(IBAction)buttonPressed:(UIButton*)sender
{
NSLog(#"%d", [sender tag]);
}