UIButton press and hold - repeat action until let go - ios

I want to have a certain method run and repeat itself for as long as someones finger is pressed down on a button. I want that method to stop repeating itself when the finger is not on the button anymore
Is there a way to check if the touchDown is still occurring during the method implementation? Help!

You can use the UIControlEventTouchDown control event to start the method running, and UIControlEventTouchUpInside, or similar, to detect when the button is no longer being "pressed".
Set up the actions to the button, e.g.:
[myButton addTarget:self action:#selector(startButtonTouch:) forControlEvents:UIControlEventTouchDown];
[myButton addTarget:self action:#selector(endButtonTouch:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
(Note the above will cause touch up inside and outside the button to invoke the endButtonTouch: method.)
Then add the startButtonTouch: and endButtonTouch methods, e.g., :
- (void)startButtonTouch:(id)sender {
// start the process running...
}
- (void)endButtonTouch:(id)sender {
// stop the running process...
}

Drawing upon the bobnoble's answer here's a helper view
#import <UIKit/UIKit.h>
#interface YOIDCAutorepeatingButton : UIButton
// you COULD pinch pennies switching to nonatomic, but consider
// how much time it would take to debug if some day some moron decides without checking this spec
// to alter this prop off another thread
#property (atomic) NSTimeInterval delayUntilAutorepeatBegins;
#property NSTimeInterval delayBetweenPresses;
#property (weak) id<NSObject> recipient;
#property SEL touchActionOnRecipient;
#end
-------------> .m
#import "YOIDCAutorepeatingButton.h"
#interface YOIDCAutorepeatingButton()
{
NSTimeInterval _pressStartedAt;
}
#end
#implementation YOIDCAutorepeatingButton
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self addTarget:self action:#selector(startButtonTouch:) forControlEvents:UIControlEventTouchDown];
[self addTarget:self action:#selector(endButtonTouch:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
self.delayUntilAutorepeatBegins = .250;
self.delayBetweenPresses = .080;
}
return self;
}
-(void)killLastCharacter:(id)sender
{
[self.recipient performSelector:self.touchActionOnRecipient withObject:sender];
}
- (void)performAutorepeat:(id)sender
{
if(!self.delayBetweenPresses) {
// bail
return;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.delayBetweenPresses * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(_pressStartedAt) {
[self killLastCharacter:sender];
[self performAutorepeat:sender];
}
});
}
- (void)startButtonTouch:(id)sender {
[self killLastCharacter:sender];
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
_pressStartedAt = now;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.delayUntilAutorepeatBegins * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(_pressStartedAt) {
[self killLastCharacter:sender];
[self performAutorepeat:sender];
}
});
}
- (void)endButtonTouch:(id)sender {
_pressStartedAt = 0;
}
#end
-------- sample usage -------
- (IBAction)killLastDigit:(id)sender {
.....
- (void)viewDidLoad
{
assert(self.backSpace);
[YOIDCAutorepeatingButton class]; // if xib is in a bundle other than main gottal load the class
// otherwise you'd get -[UIButton setRecipient:]: unrecognized selector sent to instance
// on setRecipient:
self.backSpace.recipient = self;
self.backSpace.touchActionOnRecipient = #selector(killLastDigit:);

Related

Xcode (Objective C) - Error regarding interface?

I'm a beginner to Xcode nd Objective-C! I'm making an ios app which is basically a stop watch. The idea is only to have two buttons. One to reset the stopwatch and the other to start and stop the clock. (Basically, you click the start button which then turns into a stop button which when clicked will stop the stopwatch. The problem is I have two errors which are the same and read the following: (I don't know how to fix them which is the question!)
No visible #interface fro 'UIButton' declares the selector 'setTitle:forControlState:'
This has come up twice at two points! Point one:
[button setTitle:#"Start" forControlState:UIControlStateNormal];
And point two...
[button setTitle:#"Stop" forControlState:UIControlStateNormal];
Here is my code for VeiwController.h:
//
#import <UIKit/UIKit.h>
float addingtheTime;
#interface ViewController : UIViewController
{
IBOutlet UILabel *Label;
NSTimer *Timer;
}
#end
Here is my code for ViewController.m
//
#import "ViewController.h"
#interface ViewController ()\
#end
#implementation ViewController
-(IBAction)Start:(id)start
{
UIButton *button = (UIButton *)start;
if (button.tag == 0){
button.tag = 1;
[button setTitle:#"Start" forControlState:UIControlStateNormal];
Timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(addingthetime) userInfo:nil repeats:YES];
}else {
button.tag = 0;
[button setTitle:#"Stop" forControlState:UIControlStateNormal];
//Invoke your method to stop Timer.
}
}
-(IBAction)Restart:(id)sender
{
[Timer invalidate];
addingtheTime = 0;
Label.text = [NSString stringWithFormat:#"0.00"];
}
-(void)addingthetime
{
addingtheTime = addingtheTime + 0.01;
Label.text = [NSString stringWithFormat:#"%.2f", addingtheTime];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Please note I am a beginner so please explain as much as you can and thanks you in advance for any help!!!
its forstate not forControlState
[button setTitle:#"start" forState:UIControlStateNormal];
[button setTitle:#"stop" forState:UIControlStateNormal];

iOS Objective-C block callback issue

I am trying to use pure code to create UI practice block pass value between viewController. But the callback block didn't work. The NSLog method didn't print anything on debug area. Here's the code. Give me some tips, thank you.
VC.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (copy, nonatomic) void (^callBack)(NSString *text);
#end
VC.m
- (UITextField *)textField {
if (!_textField) {
_textField = [[UITextField alloc] init];
_textField.backgroundColor = [UIColor whiteColor];
}
return _textField;
}
- (UIButton *)button {
if (!_button) {
_button = [[UIButton alloc] init];
_button.backgroundColor = [UIColor blueColor];
[_button addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
- (void)setupUI {
[self.view addSubview:self.textField];
[self.view addSubview:self.button];
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view.mas_centerX);
make.centerY.mas_equalTo(self.view);
}];
[self.button mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(200);
make.height.mas_equalTo(50);
make.centerX.mas_equalTo(self.view);
make.centerY.mas_equalTo(self.view).offset(100);
}];
}
- (void)buttonAction {
NSString *str = self.textField.text;
if (self.callBack != nil) {
self.callBack(str);
NSLog(#"This statement didnt print in log");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
}
update code
VC2.m
- (void)viewWillAppear:(BOOL)animated{
self.callBack = ^(NSString *text){
};
}
- (void)buttonAction {
if (self.callBack) {
NSLog(#"It worked on debug area %#", self.textField.text);
self.callBack(self.textField.text);
}
self.textField.text = #"";
}
VC1.m
- (void)viewDidLoad {
[super viewDidLoad];
_secondVc = [[SecondViewController alloc] init];
_secondVc.callBack = ^(NSString *str){
};
[self setupUI];
self.view.backgroundColor = [UIColor greenColor];
}
- (void)viewWillAppear:(BOOL)animated {
if (_secondVc.callBack != nil) {
NSLog(#"It wrked on debug screen");
_secondVc.callBack = ^(NSString *str){
NSLog(#"It didn't worked on debug screen");
//I want set my label.text = str;
};
};
}
The only way is that you property
#property (copy, nonatomic) void (^callBack)(NSString *text);
is empty. Try to put breakpoint in buttonAction method and look at the property.
As Sander and KrishnaCA mentioned your callBack is nil. I would suggest you create a definition of the block like this:
typedef void(^TextBlock)(NSString *text);
Then change your property to:
#property (copy, nonatomic) TextBlock callBack;
Create a copy of the block in your first view controller:
#interface FirstViewController()
#property (copy, nonatomic) TextBlock firstViewControllerCallBack;
#end
Initialize the callback copy (i.e. in viewDidLoad)
- (void)viewDidLoad {
[super viewDidLoad];
self.firstViewControllerCallBack = ^(NSString *text){
NSLog(#"Second view controller's button tapped!");
};
}
Assign the callback to the second view controller right before presenting/pushing it:
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.callBack = self.firstViewControllerCallBack; // Assign the callback
// ... Presenting the view controller
Clean up the completion block after you done with it (i.e. in viewWillDisappear):
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.firstViewControllerCallBack = nil;
}

IBAction disabling not working

If the user keeps clicking on button1 one or two , progress2.progress keeps increasing/decreasing on each click and progress1.progress keeps the same value until the user stops clicking. And in case he will surely lose , if he also keeps clicking nothing happens until he stops clicking. I don't want it to be that way since I want to hide/disable the buttons as soon as it's confirmed that he's losing to fix this issue. Any way to fix that?
Here is my .m :
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (BOOL)prefersStatusBarHidden { return YES; }
- (void)viewDidLoad
{
progress1.progress=arc4random() % 11 * 0.1;
count1=0;
count2=0;
label1.hidden = NO;
gameOver.hidden = YES;
score=0;
[super viewDidLoad];
;
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)regulator{
if(timer1)
{
[timer1 invalidate];
timer1 = nil;
}
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
}
timer4 =[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(conditioner) userInfo:nil repeats:YES];
;}
-(void)conditioner {
if (fabs(progress2.progress-progress1.progress)<=0.25 )
{
score=score+1;
scorenumber.text= [NSString stringWithFormat:#"%i",score];
[self newGame];
;
} else{
stop1=YES;
stop2=YES;
gameOver.hidden=NO;
stick.hidden=YES;
bg.hidden=YES;
progress1.hidden=YES;
progress2.hidden=YES;
supply.hidden=YES;
demand.hidden=YES;
}}
-(void)newGame{
progress1.progress=arc4random() % 11 * 0.1;}
- (IBAction)start:(UIButton *)sender {
progress2.progress=arc4random() % 11 * 0.1;
if(timer4)
{
[timer4 invalidate];
timer4 = nil;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(regulator) userInfo:nil repeats:YES];
[self regulator];
stop1=NO;
stop2=NO;
label1.hidden=YES;
UIButton *button1 = (UIButton *)sender;
button1.enabled = NO;
UIButton *button2 = (UIButton *)sender;
button2.enabled = NO;
}
- (IBAction)button1:(UIButton *)sender {
if(stop1==YES){button12.hidden = TRUE;}
progress2.progress=progress2.progress-0.05;
;
[self regulator];
count2=0;
count1 = count1 +1;
}
- (IBAction)button2:(UIButton *)sender {
[self regulator];
progress2.progress=progress2.progress+0.05;
if(stop2==YES){button22.hidden = TRUE;}
count1 =0;
count2 = count2+1;
}
#end
and my .h:
#import <UIKit/UIKit.h>
int count1;
int count2;
int score;
void *regulator;
void *newGame;
void *conditioner;
BOOL stop1;
BOOL stop2;
void *firstLaunch;
#interface ViewController : UIViewController{
IBOutlet UILabel *scorenumber;
IBOutlet UIImageView *stick;
IBOutlet UILabel *label1;
IBOutlet UIImageView *bg;
IBOutlet UILabel *supply;
IBOutlet UILabel *demand;
IBOutlet UILabel *gameOver;
IBOutlet UIProgressView *progress1;
IBOutlet UIProgressView *progress2;
IBOutlet UIButton *button12;
IBOutlet UIButton *button22;
NSTimer *timer1;
NSTimer *timer2;
NSTimer *timer3;
NSTimer *timer4;
}
- (IBAction)button1:(UIButton *)sender;
- (IBAction)button2:(UIButton *)sender;
#end
Thanks a lot for any help or information. I edited my question with the full code to give further explanation about the issue I'm facing. Regards.
This is actually a coding issue. MVC basics.
I believe you miss some understanding of things. So I'll explain:
IBAction - It's an action sent from the view to the controller.
IBOutlet - Meant for the controller to control the view.
On your code you are getting the sender (which should be read only when coding right) and you are trying to set it up. I assume you need to define a new IBOutlet to represent the button then connect it on your storyboard and then inside this function to make it enable/disabled.
Also a good practice would be to use "TRUE" and "FALSE" and not "YES/NO".
Hope this helps.
There are couple of ways you can approach this to make sure when user touches the button then it doesn't do anything.
It wasn't clear from your question so I assume on touch down of button you call (IBAction)button1. So Try
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so don't do anything
}
else
{
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}
If you want to hide it so that the user can't do anything try this
- (IBAction)button1:(UIButton *)sender
{
if(stop1==YES)
{
//game has stopped so hide this button
//assuming you have connected an IBOutlet to your button1
button1.hidden = YES;
}
else
{
button1.hidden = NO;
progress2.progress=progress2.progress-0.05;
[self regulator];
}
}

Using a Long Press Gesture only if certain conditions are met

I am trying to create a long press gesture that presents a second view controller, once the press has been held for 3 seconds. However, I only want the second view controller presented if the device is in a certain accelerometer orientation for the ENTIRE 3 seconds. That is, if the gesture is not held long enough or the device is tilted too much, the gesture is dismissed and the user must try again.
// In FirstViewController.h
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
#interface FirstViewController : UIViewController
#property (nonatomic, strong) CMMotionManager *motionManager;
#end
// In FirstViewController.m
#import "FirstViewController"
#import "SecondViewController"
#implementation motionManager;
- (void) viewDidLoad
{
[super viewDidLoad];
self.motionManager = [[CMMotionManager alloc]init];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 3.0;
[self.view addGestureRecognizer:longPress];
}
- (void) handleLongPress: (UILongPressGestureRecognizer *)sender
{
// Not sure what to do here
}
I have previously tried chunks of code in the last method but it looks obnoxious and just is not correct. Instead, I have listed several lines of code below that I know work individually, but I need assistance in making them all work together.
// Accelerometer
if ([self.motionManager isAccelerometerAvailable])
{
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData,NSError *error)
{
if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
{
NSLog(#"Correct Orientation!!!");
[self.motionManager stopAccelerometerUpdates];
}
else
{
NSLog(#"Incorrect orientation!!!");
[self.motionManager stopAccelerometerUpdates];
}];
}
else
{
NSLog(#"Accelerometer is not available.");
}
// Go to second view controller
if (sender.state == UIGestureRecognizerStateBegan)
{
SecondViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self presentViewController:svc animated:YES completion:nil];
}
Any ideas? Or even a more general way to cancel the gesture unless a condition is met would be very helpful.
I hope the code is verbose enough for you to read, it's pretty self explanatory - I've stuck with your accelerometer code, and used the same variable names.
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
#interface ViewController () {
NSOperationQueue *motionQueue;
NSTimer *touchTimer;
NSTimeInterval initialTimeStamp;
BOOL touchValid;
float timerPollInSeconds;
float longPressTimeRequired;
}
#property (strong, nonatomic) NSTimer *touchTimer;
#property (assign, nonatomic) NSTimeInterval initialTimeStamp;
#property (assign, nonatomic) BOOL touchValid;
#property (assign, nonatomic) float timerPollInSeconds;
#property (assign, nonatomic) float longPressTimeRequired;
#property (strong, nonatomic) CMMotionManager *motionManager;
#property (strong, nonatomic) NSOperationQueue *motionQueue;
#end
#implementation ViewController
#synthesize touchTimer = _touchTimer, initialTimeStamp, touchValid, motionQueue = _motionQueue;
#synthesize timerPollInSeconds, longPressTimeRequired, motionManager = _motionManager;
- (void)viewDidLoad
{
self.timerPollInSeconds = 0.25f;
self.longPressTimeRequired = 3.0f;
self.touchTimer = nil;
self.touchValid = NO;
self.initialTimeStamp = NSTimeIntervalSince1970;
self.motionManager = [[CMMotionManager alloc] init];
self.motionQueue = [[NSOperationQueue alloc] init];
[_motionQueue setName:#"MotionQueue"];
[_motionQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
[super viewDidLoad];
self.view.multipleTouchEnabled = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Operations
-(void) startLongPressMonitorWithTimeStamp:(NSTimeInterval) timeStamp {
NSLog(#"Starting monitoring - %g", timeStamp);
if( self.touchTimer ) {
if( [_touchTimer isValid] ) {
[_touchTimer invalidate];
}
}
self.touchTimer = [NSTimer timerWithTimeInterval:self.timerPollInSeconds target:self selector:#selector(timerPolled:) userInfo:nil repeats:YES];
if( [_motionManager isAccelerometerAvailable] ) {
NSLog(#"Accelerometer Available");
if( ![_motionManager isAccelerometerActive] ) {
NSLog(#"Starting Accelerometer");
[_motionManager startAccelerometerUpdatesToQueue:self.motionQueue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
{
dispatch_sync(dispatch_get_main_queue(), ^{
self.touchValid = YES;
});
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
self.touchValid = NO;
[self stopLongPressMonitoring:YES];
});
};
}];
}
else {
NSLog(#"Accelerometer already active");
}
}
else {
NSLog(#"Accelerometer not available");
}
self.initialTimeStamp = timeStamp;
self.touchValid = YES;
[_touchTimer fire];
[[NSRunLoop mainRunLoop] addTimer:self.touchTimer forMode:NSRunLoopCommonModes];
}
-(void) stopLongPressMonitoring:(BOOL) touchSuccessful {
[_motionManager stopAccelerometerUpdates];
[_touchTimer invalidate];
self.touchValid = NO;
if( touchSuccessful ) {
NSLog(#"Yes");
}
else {
NSLog(#"No");
}
}
#pragma mark - User Interaction
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//We're using the current times, interval since the touches timestamp refers to system boot up
// it is more than feasible to use this boot up time, but for simplicity, I'm just using this
NSTimeInterval timestamp = [NSDate timeIntervalSinceReferenceDate];
[self startLongPressMonitorWithTimeStamp:timestamp];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if( self.touchValid && [NSDate timeIntervalSinceReferenceDate] - self.initialTimeStamp == self.longPressTimeRequired ) {
[self stopLongPressMonitoring:YES];
}
else {
[self stopLongPressMonitoring:NO];
}
}
#pragma mark - Timer Call back
-(void) timerPolled:(NSTimer *) timer {
NSTimeInterval firedTimeStamp = [NSDate timeIntervalSinceReferenceDate];
NSLog(#"Timer polled - %g", firedTimeStamp);
if( self.touchValid ) {
NSLog(#"Time elapsed: %d", (int)(firedTimeStamp - self.initialTimeStamp));
if( firedTimeStamp - self.initialTimeStamp >= self.longPressTimeRequired ) {
NSLog(#"Required time has elapsed");
[self stopLongPressMonitoring:YES];
}
}
else {
NSLog(#"Touch invalidated");
[self stopLongPressMonitoring:NO];
}
}
#end
You may be able to do what you want by subclassing UIGestureRecognizer to make your own gesture recognizer similar to UILongPressGestureRecognizer that listens for accelerometer data in addition to presses of at least 3 second duration.
I'd probably override the onTouchesBegan, and onTouchesEnded methods, rather than using a gesture recogniser.
I'd then create a NSTimer object, an NSTimeInterval var and a BOOL in your view controller; for the sake of it, I'll call them, touchTimer, initialTouchTimeStamp, and touchValid.
for the sake of complexity, it's an assumption that the viewControllers view is not multi-touch.
Assume the repeatTime = 0.25f;
longPressTimeRequired = 3;
The timer selector would incorporate your accelerometer method, if the data inside your accelerometer method is invalid, I'd set a touchValid to false (and invalidate the timer), otherwise I'd set it to true After checking the accelerometer, I'd check if my initialTouchTimeStamp var is longPressTimeRequired or more seconds prior to [touchTimer fireDate] - repeatTime , if it is, and the touchValid is true, then I would go to my second controller.
onTouchesBegan, I'd invalidate touchTimer and create a new one that would repeat every repearTime seconds, and lasts for y seconds. Set touchValid to NO, and set initialTouchTimeStamp to touch.timestamp.
onTouchesEnded, I'd invalidate touchTimer, and check if my initialTouchTimeStamp var is longPressTimeRequired or more seconds prior to [touchTimer fireDate] - repeatTime , if it is, and the touchValid is true, then I would go to my second controller.
there are many common elements in here, and it's probably not the most elegant way of doing things, but it should work. Hope this helps.

UIButton class fails to recognize selector after adding as a subview to a UIView

I have a UIViewController class in which im trying to allocate a UIButton Class. Here is a sample code.
MyViewController.m
- (void)viewDidLoad
{
CGRect frame = CGRectMake(companybuttonxOffset, companybuttonyOffset, buttonWidth, buttonHeight);
CustomButton *customButton = [[CustomButton alloc]initWithFrame:frame];
[self.view addSubview:customButton];
[super viewDidLoad];
}
CustomButton.h
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton {
}
#property (nonatomic, assign) NSInteger toggle;
- (void)buttonPressed: (id)sender;
#end
CustomButton.m
#import "CustomButton.h"
#implementation CustomButton
#synthesize toggle;
- (id) initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//custom button code
[self addTarget: self action: #selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
}
return self;
}
- (void)buttonPressed: (id)sender
{
NSLog(#"buttonPressed !!!!!");
}
#end
Although the button is present in my viewcontroller, if i press the button, i keep getting this error - -[UIButton buttonPressed:]: unrecognized selector sent to instance 0xb1dca50
From what i understand after searching for a lot for an answer is that, initWithFrame never gets called when you subclass the button in IB. Instead i should use initWithCoder. Is this right ? If this is it, then i have no idea what NSCoder is, and how i can use it.
Im tired of searching for a solution for this, please help me out guys.
I guess that in the IB, you have not changed your button's class to CustomButton.
Therefore, it is still a UIButton.
Nonetheless, I back rdelmar here that this is not a very good design.
Your view controller should handle the event, not the button itself.
While I agree you should usually have all targets be in the controller layer, give this a try:
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super initWithCoder:coder])
{
[self customButtonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self customButtonInit];
}
return self;
}
- (void)customButtonInit
{
[self addTarget: self action: #selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
}

Resources