Tutorial :How to properly invalidate an NSTimer


I've got an iPhone app with an NSTimer called pressTimer that goes off every time someone touches this button. The problem is they touch the button a lot, and I want the timer to stop when they lift up their finger. So I declared pressTimer in my .h and synthesized it in .m then assigned and started it on the TouchDown action I created. I use the code [pressTimer invalidate] on my TouchUpInside action that should cancel the timer, since it's a global variable. It seems to cancel the timer fine, but then when I go to actually trip the timer, the program freezes up completely, even though I get no code errors or warnings. I'm a noob, so please don't be too rough :0

Update: Console logs- Thanks guys!

continue  2010-07-01 16:39:30.981 Clickkr[1573:307] -[__NSCFData invalidate]: unrecognized selector sent to instance 0x154b40  2010-07-01 16:39:30.999 Clickkr[1573:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFData invalidate]: unrecognized selector sent to instance 0x154b40'  *** Call stack at first throw:  (      0   CoreFoundation                      0x309a5fd3 __exceptionPreprocess + 114      1   libobjc.A.dylib                     0x318b58a5 objc_exception_throw + 24      2   CoreFoundation                      0x309a9a77 -[NSObject(NSObject) doesNotRecognizeSelector:] + 102      3   CoreFoundation                      0x309a8f15 ___forwarding___ + 508      4   CoreFoundation                      0x3093b680 _CF_forwarding_prep_0 + 48      5   Clickkr                             0x00002b23 -[MyViewController addOne:] + 42      6   CoreFoundation                      0x309307ad -[NSObject(NSObject) performSelector:withObject:withObject:] + 24      7   UIKit                               0x31e1f829 -[UIApplication sendAction:to:from:forEvent:] + 84      8   UIKit                               0x31e1f7c9 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 32      9   UIKit                               0x31e1f79b -[UIControl sendAction:to:forEvent:] + 38      10  UIKit                               0x31e1f4ed -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 356      11  UIKit                               0x31e1fb3b -[UIControl touchesEnded:withEvent:] + 342      12  UIKit                               0x31e1e4ed -[UIWindow _sendTouchesForEvent:] + 368      13  UIKit                               0x31e1de67 -[UIWindow sendEvent:] + 262      14  UIKit                               0x31e19b5b -[UIApplication sendEvent:] + 298      15  UIKit                               0x31e19507 _UIApplicationHandleEvent + 5022      16  GraphicsServices                    0x30a8c147 PurpleEventCallback + 666      17  CoreFoundation                      0x3097baab __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26      18  CoreFoundation                      0x3097d84f __CFRunLoopDoSource1 + 166      19  CoreFoundation                      0x3097e62d __CFRunLoopRun + 520      20  CoreFoundation                      0x309278eb CFRunLoopRunSpecific + 230      21  CoreFoundation                      0x309277f3 CFRunLoopRunInMode + 58      22  GraphicsServices                    0x30a8b6ef GSEventRunModal + 114      23  GraphicsServices                    0x30a8b79b GSEventRun + 62      24  UIKit                               0x31dc32a7 -[UIApplication _run] + 402      25  UIKit                               0x31dc1e17 UIApplicationMain + 670      26  Clickkr                             0x00002333 main + 70      27  Clickkr                             0x000022e8 start + 40  )  terminate called after throwing an instance of 'NSException'  Program received signal:  “SIGABRT”.  


This is the way I invalidate timers:

[timer invalidate];  timer = nil;  

The problem you're probably having is that once your timer is invalidated, it is removed from the runtime loop and when someone wants to access it, your program crashes. After invalidating it, just make it so that it is nil. That way if someone wants to send a message or do anything to it, it'll send it to nil.


@interface    NSTimer * yourTimer;    @property (nonatomic, retain) yourTimer;  @synthesize yourTimer;    @implement        self.yourTimer = [NSTimer scheduledTimerWithTimeInterval:5                                                      target:self                                                    selector:@selector(yourSelector)                                                    userInfo:nil                                                     repeats:NO];      //Wherever you want to stop the timer,    [yourTimer invalidate];    self.yourTimer = nil;  


The log tells something wrong with addOne ... how's it related to the timer?


Guys I figured it out after a little bit of messing with it. Anauel's method for stopping timers worked great, but for some reason my method name was clashing with the timer's selector, so I changed them both. I also added Anauel's code to the method I used as a selector. Thanks!


I would better add a check of the validity flag and timer object instance

-(void) clearKeepAliveTimer {      if(keepAliveTimer && [keepAliveTimer isValid]) {          [keepAliveTimer invalidate];          keepAliveTimer = nil;      } }  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »