简体   繁体   中英

NSTimer firing more than it should

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();

}

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];
}

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] ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM