在进入后台和在前台检索时将 NSTimer 的时间保存到磁盘

Posted

技术标签:

【中文标题】在进入后台和在前台检索时将 NSTimer 的时间保存到磁盘【英文标题】:Saving NSTimer's time to disk on entering background and retrieving on foreground 【发布时间】:2013-08-11 18:53:32 【问题描述】:

我希望我的计时器在后台工作,我想出真正做到这一点的唯一方法是在appliationDidEnterBackground 上保存时间并使用applicationDidLaunchWithOptions. 检索它我的计时器使用核心数据和我的 timeInterval (testTask .timeInterval) 在每次递减后保存如下:

-(IBAction)startTimer:(id)sender
    if (timer == nil) 
        [startButton setTitle:@"Pause" forState:UIControlStateNormal];
       timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
     else 
        [startButton setTitle:@"Resume" forState:UIControlStateNormal];
        [timer invalidate];
        timer = nil;
    


-(void)timerAction:(NSTimer *)t

    if(testTask.timeInterval == 0)
    
        if (self.timer)
        
            [self timerExpired];
            [self.timer invalidate];
            self.timer = nil;
        
    
    else
    
        testTask.timeInterval--;
        NSError *error;
        if (![self.context save:&error]) 
            NSLog(@"couldn't save: %@", [error localizedDescription]);
        
    
    NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
    NSString *string = [NSString stringWithFormat:@"%02u:%02u:%02u",
                        seconds / 3600, (seconds / 60) % 60, seconds % 60];
    timerLabel.text = string;
    NSLog(@"%f", testTask.timeInterval);

-(void)timerExpired
    UILocalNotification* localNotification = [[UILocalNotification alloc] init];
    localNotification.alertBody = @"Time is up";
    localNotification.alertAction = @"Ok";
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    [[UIApplication sharedApplication]presentLocalNotificationNow:localNotification];

这些方法在一个细节视图控制器中,由这个初始化:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    DetailViewController *detailVC;
    if (![self.detailViewsDictionary.allKeys containsObject:indexPath])
        detailVC = [[DetailViewController alloc]initWithNibName:@"DetailViewController" bundle:nil];
        [self.detailViewsDictionary setObject:detailVC forKey:indexPath];
        detailVC.context = self.managedObjectContext;
    else
        detailVC = self.detailViewsDictionary[indexPath];
    
        Tasks *task = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        detailVC.testTask = task;
        [[self navigationController] pushViewController:detailVC animated:YES];
    NSLog(@"%@", self.detailViewsDictionary);

我不明白的是...我将如何访问 timeInterval(每个 detailviewcontroller 有不同的 timeinterval...)以便我可以将其放入 appliationDidEnterBackground?另外,我猜我应该保存应用程序进入后台的时间,然后保存它进入前台的时间,然后减去?然后我会从时间间隔中减去那个值,对吗?

【问题讨论】:

【参考方案1】:

首先,如果您完全关心准确性,就不应该使用这样的直接倒计时。 NSTimer 不会以精确的一秒间隔触发,延迟会累积。更好的方法是在计时器启动时创建一个NSDate,然后在每次滴答时获取NSTimeInterval,然后计算分钟和秒。

为每个视图控制器存储自己的开始时间,您可以注册任何对象来接收UIApplicationDidEnterBackgroundNotification。这是在应用委托获得applicationDidEnterBackground: 的同时发布的。

另外,我猜我应该保存应用程序进入后台的时间,然后保存它进入前台的时间,然后减去?然后我会从时间间隔中减去那个值,对吗?

是的:

NSTimeInterval idleTime = [dateReturnedToForeground timeIntervalSinceDate:dateEnteredBackground];
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:startDate];
elapsedTime -= idleTime;

会给你活动你的计时器已经过去的时间。

【讨论】:

我对第一部分有点困惑。如果我在计时器启动时创建 NSDate,我应该在 timerAction 方法中将它与什么进行比较以确保计时器按原样工作? [[NSDate date] timeIntervalSinceDate:timerStartDate];

以上是关于在进入后台和在前台检索时将 NSTimer 的时间保存到磁盘的主要内容,如果未能解决你的问题,请参考以下文章

在进入后台时将 UIDocument 上传到 iCloud

iOS 保证定时器进入后台依然运行

进入后台时使 NSTimer 无效

进入后台状态时是不是可以在 iOS 4 设备上运行 NSThread 或 NSTimer?

快速 NSTimer 在后台

我们如何让 NSTimer 在 iOS 中为我​​的音频播放器在后台运行