0

I'm currently doing this:

timer = [NSTimer timerWithTimeInterval:timeUntilAction target:self selector:@selector(actionToPerform) userInfo:nil repeats:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];

But I would like to be able to invalidate that timer. Calling invalidate doesn't seem to do anything and I don't know what else to try, since I can't remove the timer from the NSRunLoop from any instance methods that I can see for NSTimer or NSRunLoop.

How should I set a method (actionToPerform) up to fire after a certain delay (timeUntilAction), but still have the ability to cancel the action, given certain user interaction. The user should also be able to reinitiate the timer before the initial timer (one that was cancelled) was scheduled to go off.

Any suggestions would be great!

Thanks

RileyE
  • 10,874
  • 13
  • 63
  • 106
  • 2
    Just for kicks, add it to `NSDefaultRunLoopMode` instead of `NSRunLoopCommonModes`. The second one can cause unanticipated behavior in my experience (though, checking the docs, I understand why now). `invalidate` definitely will remove it from the run loop, and if it doesn't then you are doing something wrong. – borrrden Aug 13 '12 at 01:11
  • @borrrden Oh goodness. You were right. I screwed up in an if statement. Now everyone can downvote me for not fully testing my code! I was just sure that I hadn't screwed up, but I put it in one block too far. I just needed some coffee. Thanks! – RileyE Aug 13 '12 at 02:22
  • Can someone close this question? Or delete it? – RileyE Aug 13 '12 at 02:22
  • Can you not delete it yourself? I don't have an option to. – borrrden Aug 13 '12 at 02:35
  • Not with answers. A moderator will have to delete it. – RileyE Aug 13 '12 at 02:40

2 Answers2

3
[self performSelector:@selector(actionToPerform) withObject:nil afterDelay:timeUntilAction]

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(actionToPerform) object:nil]
tc.
  • 33,468
  • 5
  • 78
  • 96
1

you can Cancel NSTimer in NSRunLoop. Even if you don't find API within NSTimer nor NSRunloop, you can try CFRunLoop. according to Apple here, see how:

First,

CFRunLoopRef *cfrl = [NSRunLoop getCFRunLoop];

Then,

CFRunLoopAddTimer

void CFRunLoopAddTimer ( CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode );

CFRunLoopRemoveTimer

void CFRunLoopRemoveTimer ( CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode );

P.S. especially about

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

see Apple doc. for NSObject

Special Considerations

This method registers with the runloop of its current context, and depends on that runloop being run on a regular basis to perform correctly. One common context where you might call this method and end up registering with a runloop that is not automatically run on a regular basis is when being invoked by a dispatch queue. If you need this type of functionality when running on a dispatch queue, you should usedispatch_after and related methods to get the behavior you want.

Also, you can use MSWeakTimer on GitHub.