I have created a NSTimer in my application which gets fired after every 1 min interval. my problem is when I put the application in background and after some time say 5 min, i bring that in foreground, the timer object gets zombied.
any thoughts on this.
Perhaps invalidate the timer when the application enters the background then start it again when the application enters the foreground.
Like so:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[myTimer invalidate];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
myTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:#selector(TimerFunction) userInfo:nil repeats:YES];
}
NSTimer objects are retained when scheduled. Your timer might be invalidated for some reason and by thus, released.
Related
How can I have an NSTimer going throughout the entire time the user is in the app?
I want to be able to change view controllers and perform different functions, all while a timer is going on int the background. If the timer hits 0, then I want to fire an event. Can I also have a timer going inside the app while the app is in the background? Or even when the iPhone's screen is off?
Thanks for the answers!
Do this piece of code in the Appdelegate making the timer its property.
self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalForTimer
target: self
selector: #selector(timerExpired:)
userInfo: nil
repeats: NO];
//Run the timer on the runloop to ensure that it works when app is in background
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode: NSDefaultRunLoopMode];
Run this method in app delegate
-(void) timerfunc{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:(0.5) target:self selector:#selector(yourfunction) userInfo:nil repeats:YES ];
[pool release];
}
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~~
I have a timer that launches in viewDidLoad that looks like this
[NSTimer scheduledTimerWithTimeInterval:0.001f target:self selector:#selector(Dragon:) userInfo:nil repeats:YES];
I want to be able to change my Interval with a variable. However, any time I try to place a variable where the 0.001f is I get errors... any ideas?
I have an app that does exactly what you are asking. I allow the user to change the speed of the timer within the app so I need to make that speed a variable. Here's how I did it:
I create a timer property on my main view controller class.
I initialize the timer when the main view controller class loads.
Each time thereafter, I invalidate my timer and reset it when the value changes.
Some snippets from inside of my main view controller .m file:
//How often to switch views (float)
#define kInterval [[NSUserDefaults standardUserDefaults] integerForKey:#"interval"]
- (void) viewDidAppear:(BOOL)animated{
[self setTimer];
}
- (void) setTimer{
[self.timer invalidate];
[self setTimer: [NSTimer scheduledTimerWithTimeInterval:kInterval target:self selector:#selector(timerFired) userInfo:nil repeats:YES]];
}
Is the app returning from a background process? If so, you may need to re-set the timer. You might also want to peek at CADisplayLink: http://developer.apple.com/library/ios/#documentation/QuartzCore/Reference/CADisplayLink_ClassRef/Reference/Reference.html%23//apple_ref/doc/uid/TP40009031
#King Popsicle you can take help of this method
(void)applicationWillEnterForeground:(UIApplication *)application OR
(void)applicationDidBecomeActive:(UIApplication *)application
You can fix the things in this method regarding the timer values :)
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
I'm pretty sure this is really simple, and I'm just missing something obvious. I have an app that needs to download data from a web service for display in a UITableView, and I want to display a UIAlertView if the operation takes more than X seconds to complete. So this is what I've got (simplified for brevity):
MyViewController.h
#interface MyViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource> {
NSTimer *timer;
}
#property (nonatomic, retain) NSTimer *timer;
MyViewController.m
#implementation MyViewController
#synthesize timer;
- (void)viewDidLoad {
timer = [NSTimer scheduledTimerWithTimeInterval:20
target:self
selector:#selector(initializationTimedOut:)
userInfo:nil
repeats:NO];
[self doSomethingThatTakesALongTime];
[timer invalidate];
}
- (void)doSomethingThatTakesALongTime {
sleep(30); // for testing only
// web service calls etc. go here
}
- (void)initializationTimedOut:(NSTimer *)theTimer {
// show the alert view
}
My problem is that I'm expecting the [self doSomethingThatTakesALongTime] call to block while the timer keeps counting, and I'm thinking that if it finishes before the timer is done counting down, it will return control of the thread to viewDidLoad where [timer invalidate] will proceed to cancel the timer. Obviously my understanding of how timers/threads work is flawed here because the way the code is written, the timer never goes off. However, if I remove the [timer invalidate], it does.
I think there is a problem with scheduling a timer and doing a blocking call on the same thread. Until the blocking call is completed, the run-loop cannot fire the timer.
I suggest you to detach a thread to perform the long operation. Once the long operation is finished, call back on the main thread to invalidate the timer.
Note: it is important to invalidate the timer on the same thread it was scheduled.
- (void)viewDidLoad {
timer = [NSTimer scheduledTimerWithTimeInterval:20
target:self
selector:#selector(initializationTimedOut:)
userInfo:nil
repeats:NO];
[NSThread detachNewThreadSelector:#selector(doSomethingThatTakesALongTime:) toTarget:self withObject:nil];
}
- (void)doSomethingThatTakesALongTime:(id)arg {
sleep(30); // for testing only
// web service calls etc. go here
[self performSelectorOnMainThread:#selector(invalidate) withObject:nil waitUntilDone:NO];
}
- (void)invalidate {
[timer invalidate];
}
- (void)initializationTimedOut:(NSTimer *)theTimer {
// show the alert view
}
Have you tried to use [NSThread sleepforTimeInterval:30]; ?
The sleep() occurs on the main thread and the associated run loop never has the chance to invoke the selector for the timer.
If you would do real work in -doSomething that doesn't block the thread, e.g. non-blocking calls to web-services, it would work as expected. Blocking calls however would have to be done in a different thread so the main run loop does not get blocked.