Releasing an NSTimer iPhone? - iphone

I have an NSTimer declared in my .h and in the viewDidLoad of the /m I have the code:
timer = [NSTimer scheduledTimerWithTimeInterval:kComplexTimer target:self selector:#selector (main) userInfo:nil repeats:YES];
I also have [timer release]; in my dealloc.
However when I exit the view and return to it, the timer has not in fact released, it has doubles in speed! How do I solve this & what am I doing wrong???
Thanks

you don't need to release it as you have not retained it - as a rule.
all you need to do is just call [timer invalidate]; which will stop your timer.

Nice Answer , but good to check whether the time is nil or not to avoid unwanted exception..
if( timer ! = nil )
{
[timer invalidate];
timer = nil;
}
Thank you...

[timer invalidate];
timer = nil;
The second line is important if you want to reset the NSTimer

You must not call release on a object that it not be created by "new", "alloc", "retain", "copy".
In this case, you had created a Timer by scheduledTimerWithTimeInterval method, So you must not call release method but call [timer invalidate] to stop the timer.

Related

I want to invalidate all [self performSelector:#selector(showLyrics) withObject:nil afterDelay:2];

I am adding
[self performSelector:#selector(showLyrics) withObject:nil afterDelay:20];
but if user restart the song then the this selector should not get performed. So I just want to
know how I can cancel that. Because after 20 second it will get invoked but I don't want that, and reschedule
[self performSelector:#selector(showLyrics) withObject:nil afterDelay:20];
I'v so many
[self performSelector:#selector(showLyrics) withObject:nil afterDelay:2];
I want to cancel all those, which I've scheduled before.
[[NSRunLoop currentRunLoop] cancelPerformSelector:#selector(showLyrics)
target:self
argument:nil];
You can use NSTimer instead of performSelector:withObject:afterDelay:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:20 target:self selector:#selector(showLyrics) userInfo:nil repeats:NO];
To cancel:
[timer invalidate];
But you may want to invalidate before you start each time or keep timers in an array and iterate through them to cancel all of them.
Use an NSTimer and save a reference to it instead of performSelector. Afaik performSelector can't be cancelled. Edit: Apparently it can be cancelled, see omz's answer...
self.showLyricsTimer = [NSTimer scheduledTimerWithTimeInterval:20.0
target:self
selector:#selector(showLyrics)
userInfo:nil
repeats:NO];
To cancel the timer you use:
[self.showLyricsTimer invalidate];
But be careful to also invalidate the timer when your view disappears f.e. in the viewWillDisappear callback, since NSTimer retains it's target.
Cancels perform requests previously registered with performSelector:withObject:afterDelay:
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument
It seems this is what you are looking for or what you were looking for~~

How to correctly invalidate my timer in NSRunLoop

I get information from a server in my app with a secondsToEnd value and I start a counter after I've received this information.
My project contains a scrollview, so to get around locking my timer due to scrolling around I add the timer to the NSRunLoop in the following way:
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSRunLoopCommonModes];
I made a NSTimer property called, how original, timer and this is the whole snippet of my startTimer function:
- (void)startTimer
{
if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];
NSTimer * timer = [[NSTimer alloc] initWithFireDate:[NSDate date]
interval:1.0
target:self
selector:#selector(timer:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSRunLoopCommonModes];
[self setTimer:timer];
[timer release];
}
The reason for the check to invalidate in the start method is because after the secondsToEnd value hits 0, I receive a new one and I call startTimer again.
And in my dealloc method I have this:
if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];
But it doesn't get invalidated? What am I doing wrong?
What order do these comma separated statements execute in? What happens if _timer is nil when you call invalidate or when you call release?
if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];
Try this instead, there is no need to check whether _timer is already nil. If it was nil then the method call does nothing.
if ([_timer isValid]) {
[_timer invalidate];
}
[_timer release];
In the dealloc method there is no need to set _timer = nil, its storage is gone after this method ends.
You should first call [timer release] and then timer = nil. Same in dealloc method. The dealloc method might no get called immediately if outer objects are in autrelease pools. In these cases it is called when the system decides to drop your object finally. So it may take some time (if you set a breakpoint).
BTW I would suggest to avoid comma syntax and use blocks within curly braces instead. It's far more easier to read.

Stopping a 'performSelector afterDelay' before it fires

I start a repeating NSTimer after a 4 second delay using the following code:
- (void)viewDidLoad {
[self performSelector:#selector(startTimer) withObject:self afterDelay:4];
}
- (void)startTimer {
NSTimer *mytimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(doSomething) userInfo:nil repeats:YES];
}
- (void)doSomething {
NSLog(#"What up!");
}
Problem is I may need to cancel startTimer from being called before the 4 seconds is up. Is there a way of doing this? I'd actually prefer to not use the performSelector in the first place (seems messy). If only NSTimer had something along the lines of this…
NSTimer *mytimer = [NSTimer
scheduledTimerWithTimeInterval:1.0
afterDelay:4.0 target:self
selector:#selector(doSomething)
userInfo:nil repeats:YES];
…then that would be perfect as I could just call the following:
[myTimer invalidate];
Any help or tips are much appreciated =)
P.S. I've found something called cancelPreviousPerformRequestsWithTarget in the NSObject class reference. Doesn't seem to be a method I can call from where this code runs however. If that's getting back on the right track your feedback is welcome!
Plz go through the SP post link
Stopping a performSelector: from being performed
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(sr)
object:nil];
The documentation for -performSelector:withObject:afterDelay: points you to the methods for canceling a queued perform request.
[myTimer invalidate] doesn't work?
Just keep a track of the object in your class, or in a centralized store for example.
If you do so, you could access your timer from everywhere you want, and invalidate it whenever it is needed
Use the NSTimer to fix issue.
self.autoTimer = [NSTimer timerWithTimeInterval:3.0 target:self
selector:#selector(connectionTimeout:) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:autoTimer
forMode:NSDefaultRunLoopMode];
and call when you want to stop timer
[self.autoTimer invalidate];
self.autoTimer = nil;

Question about NSTimer and retain

This code works well
#property (nonatomic, retain) NSTimer *timer;
self.timer = [[NSTimer timerWithTimeInterval:kAdsAppearTimeInterval target:self selector:#selector(timerFired:) userInfo:nil repeats:NO] retain];
this code get CFRelease . But why? i use retain property
self.timer = [NSTimer timerWithTimeInterval:kAdsAppearTimeInterval target:self selector:#selector(timerFired:) userInfo:nil repeats:NO];
Not a lot to go on... but:
#property (nonatomic, retain) NSTimer *timer;
self.timer = [[NSTimer timerWithTimeInterval:kAdsAppearTimeInterval target:self selector:#selector(timerFired:) userInfo:nil repeats:NO] retain];
That'll end up retaining the timer 3 times and self once.
Timer +1 for -retain
Timer +1 for scheduling it
Timer +1 for the property assignment
self +1 for being the target of the timer
The timer will be released once when fired (because it'll be unscheduled from the run loop). self will be released when the timer is invalidated or released (you shouldn't have to care).
So, you have two retain counts to account for. The call to retain in the code above is noise; don't bother as the property assignment will retain it.
That leaves the property's retain. The most obvious way is to release the timer in -dealloc.
However, unless you need to potentially invalidate the timer before it fires, there is no reason to have an instance variable referring to the timer at all. Even if you do have an iVar, there is no reason to retain the timer either as long as you set self.timer = nil in your timerFired: method (and set it to nil if you invalidate anywhere).
For a non-repeating timer, if you need a reference to the instance variable, I would not recommend a retain property in its declaration to avoid confusion.
setting the instance variable (myTimer)
myTimer = [NSTimer scheduledTimerWithTimeInterval:myTimerInterval
target:self
selector:#selector(myTimerFired:)
userInfo:nil
repeats:NO];
when the timer fires, you can mark the instance variable as nil since its released when the timer is fired
- (void) myTimerFired: (NSTimer *) theTimer{
myTimer = nil;
//etc
}
This way if you have to reference your instance variable (for example to disable the timer when exiting a View controller)
-(void) onBack {
if(myTimer){
[myTimer invalidate];
myTimer = nil;
}
}

Invalidate an NSTimer when going into background

I'm trying to invalidate a timer when my app goes into background. The timer gets invoked when you hit a button that starts the timer and is in the TimerController.m file. Here is how it gets invoked.
mytimer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];//Timer with interval of one second
[[NSRunLoop mainRunLoop] addTimer:mytimer forMode:NSDefaultRunLoopMode];
Now, I'd like to invalidate mytimer when the app goes into background, so I tried putting
[mytimer invalidate];
into the - (void)applicationDidEnterBackground:(UIApplication *)application method the apps delegate. But this won't work since it's undeclared in the delegate. I thought by including TimerController.h into the delegate, this would work, but it won't.
So, I clearly don't know what I'm doing here. Can you help? How do it get it so that mytimer is invalidated when the app goes into background?
There’s also a UIApplicationDidEnterBackgroundNotification notification posted when the application goes into background. You can subscribe for this notification in your controller and handle the transition there:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(goBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
// and later:
- (void) goBackground {
[timer invalidate], timer = nil;
}
if (timer) {
[timer invalidate];
timer = nil;
}
in applicationReEnteredForeground notification method will also work