NCoder
NCoder

Reputation: 335

NSTimer Not Stopping When Invalidated

I have the following code in my .h file:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <AVFoundation/AVFoundation.h>
#import <MapKit/MapKit.h>

@interface LandingController : UIViewController<CLLocationManagerDelegate> {
    CLLocationManager *LocationManager;
    AVAudioPlayer *audioPlayer;

}

@property (nonatomic, retain) NSTimer *messageTimer;

- (IBAction)LoginButton:(id)sender;

@end

I have the following code in my .m file:

@interface LandingController ()

@end

@implementation LandingController
@synthesize messageTimer;

- (void)checkForMessages
{

    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"BINGO:"
                          message:@"Bingo This Works"
                          delegate:nil
                          cancelButtonTitle:@"Okay"
                          otherButtonTitles:nil];

    [alert show];

}

- (IBAction)LoginButton:(id)sender {

    if ([UserType isEqualToString:@"Owner"]) {

        if (messageTimer){ 
        [self.messageTimer invalidate];
        self.messageTimer = nil;
        }

    } else {

        if (!messageTimer){

           self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                    selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:YES];


        }
    }

}

@end

But my timer doesn't want to stop when I call the invalidate.

The LoginButton is only pressed twice, once when the strResult is = to "Guard" and then the application changes it to be equal to "Owner" and the user presses the login button again, so I don't think I'm setting multiple timers.

After pressing the login button and starting the timer I segue to another view and then segue back to press the login button once more which is when I want the timer to stop. Do I need to do anything special to get the messageTimer since I switched views for a moment and then came back?

Any ideas?

Thanks!

Upvotes: 9

Views: 14175

Answers (7)

Satish Mavani
Satish Mavani

Reputation: 5085

Its weird but invalidating passed timer reference and created timer reference worked for me.

    delayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateDelayLable:) userInfo:nil repeats:YES];

    -(void)updateSendDataDelayLable:(NSTimer*)timer{
delayValueForGNSS--;

                if (delayValueForGNSSSend==0) {
                     [timer invalidate];
                     timer = nil;
                     [delayTimer invalidate];
                     delayTimer = nil;
                }
            }

Upvotes: 0

robbartoszewski
robbartoszewski

Reputation: 896

You need to call [self.messageTimer invalidate] on the same thread on which you created the timer. Just make sure that the timer is created and invalidated on main thread.

dispatch_async(dispatch_get_main_queue(), ^{
    if ([UserType isEqualToString:@"Owner"]) {
        [self.messageTimer invalidate];
        self.messageTimer = nil;
    } else {
        self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                                           selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:YES];
    }
});

Upvotes: 37

Gourav Joshi
Gourav Joshi

Reputation: 2419

I have an approach for stopping or deactivate the timer, Before apply this make sure that you tried all the cases as mentioned above so you can also understand that why this approach used at last.

 // Instead of self use NSTimer class, it will not provide you any crash and in selector placed any empty function and setRepeats to NO

self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:100.0
                       target:NSTimer selector:@selector(emptyFunctionCalling)
                                                                   userInfo:nil
                                                                    repeats:NO];
[self.messageTimer invalidate];
 self.messageTimer = nil;

So whenever the case occured that timer will not stopping then entering in this code the timer will stops permanently.

Upvotes: 1

Dmitry Shevchenko
Dmitry Shevchenko

Reputation: 32434

NSTimer is retained by NSRunLoop, so the only way I see your issue happening is if you're actually creating more than one timer and invalidating only what you have reference to.

Example:

if(!timer)
        timer = [NSTimer scheduledTimerWithTimeInterval:1 target:(self) selector:@selector(processTimer) userInfo:nil repeats:YES];

Upvotes: 20

Amin Negm-Awad
Amin Negm-Awad

Reputation: 16660

If the code at the end (starting with if) is called twice with UserType != Owner, you create a new timer without invalidating the old one. Now two timers are running. If the code executes a third time, you will add a third timer and so on. Executing the code with UserType == Owner only invalidates the last timer and even it is called repeatly, it does not invalidate older timers.

You have a timer leak. ;-)

Upvotes: 2

Ooops
Ooops

Reputation: 269

How about put an NSLog in your checkForMessages method? It would be easier to check if there's really only 1 timer.

(I'd rather put this in a comment, but I don't have that much reputation....)

Upvotes: 1

wesley
wesley

Reputation: 859

Have you try to put repeat as No

self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
                                                             target:self
                                                          selector:@selector(checkForMessages)
                                                           userInfo:nil
                                                            repeats:NO];

Upvotes: 3

Related Questions