Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kill a selector that is set to fire after a delay (on the iPhone)?

If I have a view with a performSelector set to fire after a delay:

[self performSelector:@selector(generateBall) withObject:NULL afterDelay:1.5];

...but I removeFromSuperview that view before the selector fires (for example, due to user interaction), then my app crashes.

Is there a way to kill the delayed selector in the dealloc method for that view?

EDIT:

I've tried both:

[[NSRunLoop mainRunLoop] cancelPerformSelector:theBall target:self argument:nil];

and

[[NSRunLoop currentRunLoop] cancelPerformSelector:theBall target:self argument:nil];

and while both work (allowing me to load a new view), loading the previous view ends up giving me a gray screen.

I haven't been able to find any tutorials or other information about cancelPerformSelector other than those Apple docs that were listed, and the documentation on threads and run loops seem to be very convoluted (mostly because they don't list working code samples, which would make it easier for me to step through and understand what was going on).

like image 458
Jeffrey Berthiaume Avatar asked Jul 14 '09 03:07

Jeffrey Berthiaume


3 Answers

Because I'm using performSelector:afterDelay, the only way I've been able to properly "kill" any previously requested but not launched functionality is using:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:theBall object:nil];

The following code sample shows how this works (create a new View template XCode project called "select", and replace the selectViewController.h file with this):

#import "selectViewController.h"

@implementation selectViewController

UILabel *lblNum;
UIButton *btnStart, *btnStop;
int x;

- (void) incNum {
    x++;
    lblNum.text = [NSString stringWithFormat:@"%i", x];
    [self performSelector:@selector(incNum) withObject:NULL afterDelay:1.0];
}

- (void) stopCounter {
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(incNum) object:NULL];
}

- (void)viewDidLoad {
    x = 0;

    lblNum = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    lblNum.textAlignment = UITextAlignmentCenter;
    [self.view addSubview:lblNum];

    btnStart = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btnStart.frame = CGRectMake(40, 270, 240, 30);
    [btnStart setTitle:@"start" forState:UIControlStateNormal];
    [btnStart addTarget:self action:@selector(incNum) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnStart];

    btnStop = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btnStop.frame = CGRectMake(40, 310, 240, 30);
    [btnStop setTitle:@"stop" forState:UIControlStateNormal];
    [btnStop addTarget:self action:@selector(stopCounter) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnStop];

    [self performSelector:@selector(incNum) withObject:NULL afterDelay:1.0];
    [super viewDidLoad];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}

- (void)dealloc {
    [lblNum release];
    [super dealloc];
}

@end
like image 134
Jeffrey Berthiaume Avatar answered Oct 15 '22 16:10

Jeffrey Berthiaume


-cancelPerformSelectorsWithTarget:

or

-cancelPerformSelector:target:argument:

like image 39
kperryua Avatar answered Oct 15 '22 16:10

kperryua


I've found that this works great:

[NSObject cancelPreviousPerformRequestsWithTarget:self];
like image 3
Andrew Bennett Avatar answered Oct 15 '22 14:10

Andrew Bennett