iAkshay
iAkshay

Reputation: 1263

UIBackgroundTaskIdentifier running NSTimer but not updating UILabel - iOS

In my app, I have NSTimer which updates UILabel every second. I've added UIBackgroundTaskIdentifier before NSTimer to let it run in background.

__block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                    [[UIApplication sharedApplication] endBackgroundTask:bgTask];
                    bgTask = UIBackgroundTaskInvalid;
                }];


timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];

[[NSRunLoop mainRunLoop] addTimer:updateTimer forMode:NSRunLoopCommonModes];

. . .

-(void)updateTime
{
    secondsLeft -= 1;
    //NSLog(@"Update time : %d ......",secondsLeft);
    dispatch_async(dispatch_get_main_queue(), ^{
         _timeLbl.text = [NSString stringWithFormat:@"%d",secondsLeft];
    }); 
}

Problem is when we press home button app gets into background, timer is running but uilabel is not updating. E.g. Say, _timeLbl displaying '45'. Now if I press home button, app goes into background. After 10 sec. I click app icon to get app in foreground, and there I see '45' for a while (fraction of second) and then it display 35, instead of directly display 35. That means label is not getting updated with NSTimer. Is there any workaround to solve this ?

Thanks !

Upvotes: 1

Views: 1276

Answers (7)

KKRocks
KKRocks

Reputation: 8322

You need to use CLLocation Manager's api for background timer update otherwise NSTimer allow 10 min execution in background .

try this : https://stackoverflow.com/a/38472381/3901620

and also add this in info.plist

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

Upvotes: 0

Dishant Rajput
Dishant Rajput

Reputation: 1357

App Delegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{

[[UIApplication sharedApplication]setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

}



- (void)applicationWillResignActive:(UIApplication *)application {

[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

}];
 }

YOUR CONTROLLER.M

- (void)viewDidLoad {

[super viewDidLoad];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];

}

-(void) timerTick:(NSTimer *)timer1 {

int seconds = pauseTaskTime % 60;
int minutes = (pauseTaskTime - seconds) / 60;

lblTimer.text = [NSString stringWithFormat:@"%d:%.2d", minutes, seconds]
 }

When you complete your code then follows these steps :

1. Go to your project name.

2. Click Capabilities

3. On your Background Modes. 

Thank You

Upvotes: 1

Dishant Rajput
Dishant Rajput

Reputation: 1357

Use this Code

[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
loop = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(Update) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:loop forMode:NSRunLoopCommonModes];

Upvotes: 0

Subhajit Halder
Subhajit Halder

Reputation: 1423

In your method -(void)updateTime after setting the text in your label write [_timeLbl layoutIfNeeded];.

E.g:

-(void)updateTime
{
    secondsLeft -= 1;
    //NSLog(@"Update time : %d ......",secondsLeft);
    _timeLbl.text = [NSString stringWithFormat:@"%d",secondsLeft]; 
   [_timeLbl layoutIfNeeded];
}

layoutIfNeeded checks that the view is needed to be updated or not and updates if needed. I one word it refreshes the view.

Upvotes: 0

Logic
Logic

Reputation: 705

this is working fine for me.

 [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
    countDown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeLeftSinceDate) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:countDown forMode:NSRunLoopCommonModes];

Upvotes: 0

Windindi
Windindi

Reputation: 412

Try updating the label using a reference date instead of instance variable secondsLeft.

secondsLeft = [[NSDate date] timeIntervalSinceDate:referenceDate]

Upvotes: 0

Pushkraj Lanjekar
Pushkraj Lanjekar

Reputation: 2294

Try this

-(void)updateTime {
    secondsLeft -= 1;
    //NSLog(@"Update time : %d ......",secondsLeft);
    dispatch_async(dispatch_get_main_queue(), ^{
        timeLbl.text = [NSString stringWithFormat:@"%d",secondsLeft];
    });
}

If you change it on main queue, it will get updated. I faced it long back and sorted in this way.

Upvotes: 0

Related Questions