iOS-UIButton custom target - ios

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.

Related

Calling a button click event in another function iOS objective-c

I have a trigger to catch the button click on my controller like this
[saveButton addTarget:self action:#selector(save:) forControlEvents:UIControlEventTouchUpInside];
and the relevant function is
- (void)save:(id)sender {
//implementation code
}
How do call this function in another function, I try to call this function like as follow but it showing error.
(void)checkStatus{
if(somecondition){
[self save];
}
}
Note that I am new to iOS and Objective-C and I am editing a code of another developer. Please give me a solution.
your button action has a parameter , so you need to append in the parameter as nil or self.do like
- (void)checkStatus{
if(somecondition){
[self save:nil];
}
}

Adding target to UIButton from category

I'm implementing a function to create a custom UIAlertView. I have extended UIView with a category, and I'm creating my method, called
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
I want to add a selector to a button inside my custom alertview, but this selector is contained in my UIViewController. Should I move the selector into the category, or somehow reference it in the viewcontroller? And If I move the selector into the category, I won't be able to access the navigationcontroller...
in UIView+Category.m:
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
{
UIView *alert = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width/2)-100, (self.frame.size.height/2)-50, 200, 100)];
UIButton *confirmButton = [[UIButton alloc] initWithFrame:CGRectMake(30,40, 50, 50)];
[confirmButton addTarget:self action:#selector(delete:) forControlEvents:UIControlEventTouchUpInside];
[alert addSubview:confirmButton];
[self addSubview:alert];
}
selector method in MyViewController.m
- (IBAction)delete:(id)sender
{
[[self.view viewWithTag:-7] removeFromSuperview];
self.navigationController.navigationBar.hidden = NO;
}
You are bumping up against the limitations of categories. You can't add instance variables to a class in a category, so you don't have a clean way to save a pointer to your presenting view controller.
I would suggest adding a new method to your category:
- (void) addButtonWithTitle: (NSString*) title
target: (id) target
action: (SEL) action
forControlEvents: (UIControlEvents)controlEvents;
Then in the implementation of that method, use the parameters that are passed in to create and configure the button. The method includes a target, selector, and list of events that should trigger the action.
The selector should be implemented in your viewController , since you could be using your alertView in different viewControllers. Therefore sometimes you would need to perform a logic specific to that viewController. Also MVC 101 forbids you from trying to implement an action in a UIView subclass. Therefore again your viewController should implement the action.

Passing parameters into a selector

I have an UIButton that is subview on an UIView. When the button is pressed, my app is supposed to pass a captured image into a function called by the #selector. However, my research shows me that I am not able to pass anything to the function with the selector of the UIButton. How can I go around this?
[hangButton addTarget:self
action:#selector(faceDetector: the image I want to pass in)
forControlEvents:UIControlEventTouchUpInside];
You should trigger your events within a handleButton press method. You don't preset arguments, buttonPress selectors pass one argument, the button that is sending the event.
[hangButton addTarget:self
action:#selector(handleButtonPress:)
forControlEvents:UIControlEventTouchUpInside];
- (void) handleButtonPress:(id)sender {
UIImage * imageToFaceDetect = // get your image
[self faceDetector:imageToFaceDetect];
}

Adding action to a UIButton in ios sdk

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

drawRect not called for custom UIButton subclass when highlighted

When using drawRect for a custom UIButton subclass, it never seems to get called to draw the button when highlighted. Do I need to call setNeedsDisplay for my button in my touch events?
I found an easy solution.
Just add the following method to your UIButton subclass:
-(void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[self setNeedsDisplay];
}
That's it!
As far as i can tell there is no straight forward way to subclass UIButton.
UIButton is not the actual class type that is returned by the initializers. UIButton is kind of a front for a series of private classes.
Say you had:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
NSLog(#"myButton type: %#", [myButton description]);
You will find the type returned in the log to be "UIRoundedRectButton". The problem with that is you would need to have extended "UIRoundedRectButton". That is not possible as it is a private class which is only ever returned to UIButton.
On top of that "UIRoundedRectButton" is not the only possible returned class all of which are private.
In other words UIButton was built in manner that is not suited to be extended.
I had the same problem and satisfying success with the following added to my UIButton subclass
- (void)awakeFromNib {
[self addTarget:self action:#selector(redraw) forControlEvents:UIControlEventAllEvents];
}
- (void)redraw {
[self setNeedsDisplay];
[self performSelector:#selector(setNeedsDisplay) withObject:self afterDelay:0.15];
}

Resources