NSTimer firing more than it should

187 views Asked by At

I do understand that it's my problem but not the problem of NSTimer but I would be really grateful if anyone could help me. In my project I need to call this method every 0.5 seconds for 2 objects. The problem is that the timer fires at different moments of time. It may immediately fire 3 or 5 times (together for for both objects) and then it'll do the same after 0.5 seconds and again, and again.

-(void) blinkLamp{
switch (currentState) {
    case blinkingGreen:
        NSLog(@"blink green lamp");
        self.greenLamp = !self.greenLamp;
        self.colorState[0] = [NSNumber numberWithBool:greenLamp];
        self.rndValuesChanged = rand();
        break;
    case blinkingYellow:
        NSLog(@"blink yellow lamp");
        self.yellowLamp = !self.yellowLamp;
        self.colorState[1] = [NSNumber numberWithBool:yellowLamp];
        self.rndValuesChanged = rand();
        break;
    default:
        break;
}
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];
}

This method is called once in the SetState method.

-(void) setState:(State)newState{
currentState = newState;
switch (newState) {
    case green:
        self.greenLamp = YES;
        self.yellowLamp = NO;
        self.redLamp = NO;
        break;
    case yellow:
        self.greenLamp = NO;
        self.yellowLamp = YES;
        self.redLamp = NO;
        break;
    case red:
        self.greenLamp = NO;
        self.yellowLamp = NO;
        self.redLamp = YES;
        break;
    case redYellow:
        self.greenLamp = NO;
        self.yellowLamp = YES;
        self.redLamp = YES;
        break;
    case off:
        self.greenLamp = NO;
        self.yellowLamp = NO;
        self.redLamp = NO;
        break;
    case blinkingGreen:
        self.greenLamp = YES;
        self.yellowLamp = NO;
        self.redLamp = NO;
        [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];
        break;
    case blinkingYellow:{
        self.greenLamp = NO;
        self.yellowLamp = YES;
        self.redLamp = NO;
        [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];
        //[self blinkLamp];

        break;}
    default:
        NSLog(@"This mode is not allowed for VehicleTL");
    break;}
NSLog(@"G - %d Y - %d R - %d", self.greenLamp, self.yellowLamp, self.redLamp);
self.colorState[0] = [NSNumber numberWithBool:greenLamp];
self.colorState[1] = [NSNumber numberWithBool:yellowLamp];
self.colorState[2] = [NSNumber numberWithBool:redLamp];
self.rndValuesChanged = rand();

}

2

There are 2 answers

1
Droppy On BEST ANSWER

You are failing to track existing timers and are, instead, creating multiple timers, which is why you are getting them firing multiple times.

Use instance variables, and only create a timer if it's currently invalid:

case blinkingGreen:
    self.greenLamp = YES;
    self.yellowLamp = NO;
    self.redLamp = NO;
    [self createBlinkingTimer];
    break;
case blinkingYellow:{
    self.greenLamp = NO;
    self.yellowLamp = YES;
    self.redLamp = NO;
    [self createBlinkingTimer];
    //[self blinkLamp];

...

- (void)createBlinkingTimer
{
    if (!self.blinkingTimer.isValid) 
        self.blinkingTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];
}
0
Paresh Navadiya On

Mistake done here scheduled timer twice which will lead to calling of same method at different time which is you don't want it;

I would prefer here to use performSelector:withObject:afterDelay: instead of NSTimer

Make changes in setState: method

Note remove line : [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];

(void) setState:(State)newState
{
   //.............

   //.............

    switch (newState) {

     //...............
    }
    //The method should be called once only
    if(self.greenLamp || self.yellowLamp)
        [self performSelector:@selector(blinkLamp) withObject:nil afterDelay:0.5];

    //.............
}

Make changes in blinkLamp: method

Note replace line : [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkLamp) userInfo:nil repeats:NO];

With : [self performSelector:@selector(blinkLamp) withObject:nil afterDelay:0.5];