NSTimer - Why does scheduledTimerWithTimeInterval work, yet initWithFireDate doesn't? - objective-c

This calls my selector repeatedly each 60 seconds as desired:
autoDeleteTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
This next line doesn't call it at all. Not initially nor after 60 seconds:
autoDeleteTimer = [[NSTimer alloc] initWithFireDate: [NSDate dateWithTimeIntervalSinceNow:1] interval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
Can anyone explain why? Thanks.

You need to add the second timer to the main loop:
[[NSRunLoop mainRunLoop] addTimer: autoDeleteTimer forMode:NSDefaultRunLoopMode];
From the documentation of the method:
- (id)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
Return Value:
The receiver, initialized such that, when added to a run loop, it will
fire at date and then, if repeats is YES, every seconds after that.
You must add the new timer to a run loop, using addTimer:forMode:.
Upon firing, the timer sends the message aSelector to target. (If the
timer is configured to repeat, there is no need to subsequently re-add
the timer to the run loop.)
NSTimer Apple Doc

Related

NSTimer doesn't get fired at specified date

I'm creating an NSTimer:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
However, the timer doesn't get fired. The method doesn't get invoked.
If I print my date I get the following:
2012-10-12 15:19:02.786 MyApp[1768:303] fire date: 2012-10-12 13:21:02 +0000
Shouldn't it be "2012-10-12 15:21:02" ? Somehow the hours are wrong. But why? If I change the Time Zone from UTC/GMT +1 hour (I'm sitting in Germany) to another, the date is still 2012-10-12 13:19:02 plus two seconds.
What am I doing wrong?
Thanks!
A time created with initWithFireDate must be added to a run loop, e.g.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Use scheduledTimerWithTimeInterval to create a timer that is automatically scheduled on the current run loop.
PS: The description method of NSDate uses always GMT, that probably explains your output.
addTimerIf you create your timer like this:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
You must add the timer in the RunLoop like this:
[[NSRunLoop currentRunLoop] addTimer:saveProgressSizeTimer forMode:NSDefaultRunLoopMode];

How to add multiple timer to a thread

I'm trying to add multiple timers to a thread, not the main thread.Here is code:
- (IBAction)addTimer:(id)sender
{
if (!_timerQueue) {
_timerQueue = dispatch_queue_create("timer_queue", NULL);
}
dispatch_async(_timerQueue, ^{
NSTimer *tempTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:tempTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
});
}
The method above is triggered by a button action. But the code in the dispatch block runs only once not matter how many times i click the button. So only one Timer in that thread. I wonder why?
The reason why you only see one timer at a time is in the last line of your dispatch block:
-[NSRunLoop run] is a blocking call that returns when the last input source of the run loop finishes and no timers are scheduled anymore.
In addition, GCD-queues are strictly FIFO and you are creating a serial queue.
Thus, the result of you tapping that button several times is a queue that gets fuller and fuller without the first block ever finishing:
Since the timer is repeating, there always is something scheduled on the run loop and thus run never returns, barring all subsequent blocks from ever being invoked.

Set time between NSTimer selector calls

Here is my code
[NSTimer scheduledTimerWithTimeInterval:0
target:self
selector:#selector(t:)
userInfo:endtime
repeats:YES ];
-(void)t:(NSTimer *)timer
{
if ([timer.userInfo timeIntervalSinceNow] < 0) {
[timer invalidate];
}
Is it possible to set the time between calls to t method, because the default is too fast for me ?
Is it possible to set the time between calls to t method, because the
default is too fast for me?
Right now you're passing 0 for the interval. Use a larger value for a longer interval:
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:60
target:self
selector:#selector(t:)
userInfo:endtime
repeats:YES ];
This schedules the timer to fire every 60 seconds.
The first parameter is the time interval (in seconds) inbetween the calls (see NSTimer doc), where you did set 0. So you can for example set 0.5 for "once ever half second" or 1 / 30.0 for "30 times a second". Note that NSTimer calls are not absolutely exact and you may have to calculate the exact time since last call if you need accuracy (e.g. animations).

After initializing a timer other code never runs

Here is a code I use to init timer:
self.timer = [NSTimer scheduledTimerWithTimeInterval:5.0f
target:self selector:#selector(tick:) userInfo:nil repeats:YES];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[currentRunLoop run];
int a = 10;
After calling "[currentRunLoop run];", "int a = 10;" doesn't perform.(even after calling tick: method by timer)
Why?
Thank you.
[Run loop run] stops there - it never goes past that line of code it just "loops"
You shouldn't need to create your own run loop usually.
If you want to achieve a timer on a separate thread just use a timer on the main thread and have the target method perform its work on a separate thread

Objective C: App freezes when using a timer

It took me hours to figure out how to implement a timer into my program, but when it runs, the app doesn't load completely as it did before the timer.
In my main.m:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
OutLauncher *theLauncher = [[OutLauncher alloc] init];
NSTimer *theTimer = [theLauncher getTimer];
[theTimer retain];
[[NSRunLoop currentRunLoop] addTimer: theTimer forMode: NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
[pool release];
return 0;
}
The file OutLauncher is being imported into that, which looks like this:
- (void)doStuff {
NSLog( #"Doing Stuff");
}
- (NSTimer *)getTimer{
NSTimer *theTimer;
theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: #selector(doStuff) userInfo:nil repeats:YES];
return [theTimer autorelease];
}
The timer works, the console updates every second with the phrase "doing stuff" but the rest of the program just won't load. It will if I comment out the code I added to int main though
A few things:
You don't need to autorelease the timer you return after setting one up with [NSTimer scheduledTimerWithTimeInterval:] It is already autoreleased.
The timer created via scheduledTimerWithInterval is already added to the default run loop. So you don't need to use the following:
[[NSRunLoop currentRunLoop] addTimer: theTimer forMode: NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
In fact, you don't even need to keep a reference to the timer unless you need to cancel it yourself.
Here is what apple has to say about what you are doing in the documentation
run
Puts the receiver into a permanent
loop, during which time it processes
data from all attached input sources.
(void)run Discussion If no input sources or timers are attached to the
run loop, this method exits
immediately; otherwise, it runs the
receiver in the NSDefaultRunLoopMode
by repeatedly invoking
runMode:beforeDate:. In other words,
this method effectively begins an
infinite loop that processes data from
the run loop’s input sources and
timers.
Manually removing all known input
sources and timers from the run loop
is not a guarantee that the run loop
will exit. Mac OS X can install and
remove additional input sources as
needed to process requests targeted at
the receiver’s thread. Those sources
could therefore prevent the run loop
from exiting.
If you want the run loop to terminate,
you shouldn't use this method.
Instead, use one of the other run
methods and also check other arbitrary
conditions of your own, in a loop. A
simple example would be:
BOOL shouldKeepRunning = YES;
// global NSRunLoop *theRL =
[NSRunLoop currentRunLoop]; while
(shouldKeepRunning && [theRL
runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]]);
where shouldKeepRunning is set to NO
somewhere else in the program.
Availability Available in iOS 2.0 and
later.
So it looks like your code is doing what it is supposed to do. It is Logging all the timer events and waiting indefinitely for the run loop.
It looks like you're making it a lot more complicated than it needs to be. You don't need to put any code in your main.m file. If you want to fire the doStuff method every second, this is all the code you need:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: #selector(doStuff) userInfo:nil repeats:YES];
You don't need to (auto)release it yourself. timer is already autoreleased. If you want to be able to cancel the timer, you will need to keep a reference of it. Then when you want to cancel, you just call invalidate and set the reference to nil.