I have a NSTimer which should be work when app in foreground but should stop when app goes to background. but if came again to foreground timer is not working. Is there any way to do that?
inbox.m
(viewDidLoad){
myTimer = [NSTimer scheduledTimerWithTimeInterval: 0.60 target: self selector: #selector(saveSlow) userInfo: nil repeats: YES];
if([[NSUserDefaults standardUserDefaults] boolForKey:#"enterBG"]==YES)
{
[myTimer invalidate];
myTimer = nil;
}
....
}
Have you reset the bool value of enterBG after the app enter foreground? If not, even the timer is generated, it'll be invalidated again later.
Another point, you generated your timer in -viewDidLoad, generally, the view life loop only invoke it one time. The next time your app enter foreground, it won't be invoked. This might be another reason why your timer won't works again. You can try put it to -viewWillAppear: instead. You need to invoke the code snippet manually.
And a suggestion, you'd better to use the related notification to handle the timer:
UIApplicationDidEnterBackgroundNotification
UIApplicationWillEnterForegroundNotification
you cant try this code in your project
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.60 target:self selector:#selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void) timerMethod{
NSLog(#"in Vijay yadav ");
}
Try to remove:
[myTimer invalidate];
myTimer = nil;
As the timer will stop working in background after 3mins. When you came to foreground, it automatically runs. By invalidating and nil, you are removing the instance of your timer. In this case you again have to intialize the timer.
Related
I am creating a game in which the user is rewarded points while the app is in the background or not running. If the application is fully closed out, they should still get points. Currently I am doing this using an NSTimer, however I have read everywhere that timers can not execute in the background. Here is what I have and how should I fix it:
- (void)applicationDidEnterBackground:(UIApplication *)application {
score = [[NSUserDefaults standardUserDefaults] integerForKey:#"score"];
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(score) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void) score{
score++;
[[NSUserDefaults standardUserDefaults] setInteger:score forKey:#"score"];
}
You can set a "end time" with NSUserDefault in applicationDidEnterBackground method.
In applicationDidBecomeActive you get the elapsed time since the "end time" and you set your score from this elapsed time.
I want to perform particular task in background continuously even my application goes in background.
Here is the code which i tried. Timer is firing only once when it enters in background.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSTimer * timer = [NSTimer timerWithTimeInterval:2.0
target:self
selector:#selector(timerTicked)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
}
- (void) timerTicked
{
NSLog(#"Timer method");
}
You can't have a timer in background. It may work for a short time but your app will quickly goes into sleep mode if you don't have a registered background mode.
Available modes may be :
Audio
Location updates
Background fetch
Others ...
Take a look at Background execution documentation for more info
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
// NotificationTimer its timer
// myMethod1 call ur method
NotificationTimer = [NSTimer scheduledTimerWithTimeInterval: Interval
target: self
selector:#selector(myMethod1)
userInfo: nil repeats:YES];
}
I think its help to u
When my app is downloading big file and user switching to the other app, i'm running background task like this:
beginBackgroundTaskWithExpirationHandler:
and then if user opening "app switcher" by double click, screenshot of my app is completely random. Sometimes it's showing view controller that was not even open in the app.
ignoreSnapshotOnNextApplicationLaunch not helping, because it's not working at all.
Apple says: Avoid updating your windows and views here: documentation, but I'm not updating views.
I'm also running timer, to check how much background time is left, and this timer is the cause of my problems. If I'm not creating it, everything is working perfect, but I cannot save download state in Expiration handler - not enough time.
How can i avoid this weird behaviour?
-(void)appDidEnterBackground {
UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
if(backgroundTimer == nil || ![backgroundTimer isValid]) {
backgroundTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0]
interval:1
target:self
selector:#selector(checkBackgroundTimeRemaining)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:backgroundTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
}
}
- (void)checkBackgroundTimeRemaining {
NSTimeInterval timeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
if(timeRemaining < 5) {
if(backgroundTimer != nil) {
[backgroundTimer invalidate];
backgroundTimer = nil;
}
[downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
[self saveResumeData:resumeData];
}];
}
}
Sometimes it's showing view controller that was not even open in the app.
This sounds really fishy and should never happen. Maybe you can add some code to show what you are doing?
ignoreSnapshotOnNextApplicationLaunch is irrelevant here since it's only used to determine what happens when the user taps on your icon again to open the app.
Did you maybe forget to call endBackgroundTask: when you've finished your background task?
I'm not sure what you intend with the timer? If it is to determine how much time is left for you to execute in the background, use UIApplication's backgroundTimeRemaining instead.
I have tried this but not working more than 180 sec in iOS 7 and Xcode 4.6.2. Please help me
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:20 target:self selector:#selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void) timerMethod{
NSLog(#"in timerMethod");
}
Unless you enable one of the Background modes, it is not gonna work.
Why?
You have around 10 minutes of background execution after this the timer is stopped by ios.
The timer will not fire after app is locked (iOS7), since ios suspends the foreground app and bgTask will not get fire again.
There is some workarounds, consider to check below question:
iphone - NSTimers in background
Scheduled NSTimer when app is in background?
NSTimer on background IS working
UIApplication *application = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier background_task = 0;
background_task = [application beginBackgroundTaskWithExpirationHandler: ^{
[application endBackgroundTask:background_task];
}];
SEL selector = NSSelectorFromString(action);
timer = [NSTimer scheduledTimerWithTimeInterval:floatUpdateInterval target:self selector:selector userInfo:nil repeats:YES];
The above code (timer) is still running even after the backgroundTimeRemaining is 0 (zero).
How could this be? Isn't there a 10 min max for the above type of approach ?
Is the above code considered "app store" safe for submission ?
You are creating a timer that is just scheduled to repeat. beginBackgroundTaskWithExpirationHandler will be called when the time is up, this is your chance to stop whatever didn't finish in time.
You should invalidate your timer in beginBackgroundTaskWithExpirationHandler.