zzzzz
zzzzz

Reputation: 1239

Second NSTimer not working?

I previously had a single NSTimer which is working fine. I have added another NSTimer to my runloop as now I need to call two functions repeatedly after a delay. Both functions have a different delay. My code is given below.

self.now = [NSDate date] ;
    self.timer = [[NSTimer alloc] initWithFireDate:self.now
                                          interval:500
                                            target:self
                                          selector:@selector(Func1)
                                          userInfo:nil
                                           repeats:YES] ;

    self.runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];
    [self.runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10000]];


    //Second timer start here.its not working.The function 'func2' is not getting called

    self.now = [NSDate date] ;
    self.timer = [[NSTimer alloc] initWithFireDate:self.now
                                          interval:60
                                            target:self
                                          selector:@selector(Func2)
                                          userInfo:nil
                                           repeats:YES] ;

    self.runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];
    [self.runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10000]];

The first NSTimer is still working but the second NSTimer doesn't work.

Upvotes: 0

Views: 772

Answers (4)

Mariano
Mariano

Reputation: 330

Declare a second property for your timers is not the solution. You just have to invalidate the old timer and allocate the new one on main thread and it will works! try this:

   dispatch_async(dispatch_get_main_queue(), ^{
    _timer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                     target:self
                                                   selector:@selector(function:)
                                                   userInfo:nil
                                                    repeats:YES];
    [_timer fire];
   });

Upvotes: 0

Rob
Rob

Reputation: 438232

While it's not good that you're overwriting your properties (it doesn't affect the timers' ability to run, individually, but it just means that you're discarding your reference to the first timer when you set the second timer, and thus you lose the ability to invalidate the first timer, should you ever need to do that), the key problem is that you're calling runUntilDate. There's no need to do that and the first runUntilDate is preventing the creation of the second timer from taking place as viewDidLoad will not proceed beyond the first runUntilDate call.

So remove both calls to runUntilDate and both timers will work fine. Use different properties to save the reference to the two timers if you want to keep a reference to both so that you can individually invalidate them if and when you no longer need them. (And it's important that you invalidate them when you no longer need them because they maintain a strong reference to self, which means that you have a "strong reference cycle".)


You could simplify the code sample:

NSDate *date = [NSDate date];

self.timer1 = [[NSTimer alloc] initWithFireDate:date
                                       interval:500
                                         target:self
                                       selector:@selector(method1:)
                                       userInfo:nil
                                        repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer1 forMode:NSRunLoopCommonModes];

self.timer2 = [[NSTimer alloc] initWithFireDate:date
                                       interval:60
                                         target:self
                                       selector:@selector(method2:)
                                       userInfo:nil
                                        repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer2 forMode:NSRunLoopCommonModes];

Or, unless you really need NSRunLoopCommonModes, you could just do:

self.timer1 = [NSTimer scheduledTimerWithTimeInterval:500
                                               target:self
                                             selector:@selector(method1:)
                                             userInfo:nil
                                              repeats:YES];

self.timer2 = [NSTimer scheduledTimerWithTimeInterval:60
                                               target:self
                                             selector:@selector(method2:)
                                             userInfo:nil
                                              repeats:YES];

And note, I'm using methods with a parameter (hence the colon with the selector):

- (void)method1:(NSTimer *)timer
{
    // do whatever
}

- (void)method2:(NSTimer *)timer
{
    // do whatever
}

Upvotes: 3

iphondroid
iphondroid

Reputation: 500

Actually the runUntilDate will cause the app to keep on running the timer and the statements after this will not be executed. Try this:

 self.now = [NSDate date] ;
self.timer = [[NSTimer alloc] initWithFireDate:self.now
                                      interval:500
                                        target:self
                                      selector:@selector(Func1)
                                      userInfo:nil
                                       repeats:YES] ;

self.runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];


//Second timer start here.its not working.The function 'func2' is not getting called

self.now = [NSDate date] ;
self.timer = [[NSTimer alloc] initWithFireDate:self.now
                                      interval:60
                                        target:self
                                      selector:@selector(Func2)
                                      userInfo:nil
                                       repeats:YES] ;

self.runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];

Even if you use the same timer variable for both timers, it will work. But as pointed out in other answers, you lose the ability to invalidate the first timer. Just comment out the runUntilDate statements in both places.

Upvotes: 0

Volker
Volker

Reputation: 4658

You have to declare a second property of NSTimer. Currently you are overwriting your first timer when doing this

self.timer = [[NSTimer alloc] initWithFireDate:self.now
                                      interval:60
                                        target:self
                                      selector:@selector(Func2)
                                      userInfo:nil
                                       repeats:YES] ;

Declare timer2 in your interface analogues to your timer declaration and the use self.timer2 to store the second timer.

Upvotes: 2

Related Questions