NSTimer 和 NSUserDefaults

NSTimer and NSUserDefaults

计时器将是 23 小时,格式为 00:00:00(小时:分钟:秒),因此当按下按钮时,计时器将开始倒计时 23 小时,我希望将其保存通过 NSUserDefaults,所以每当我退出应用程序或切换到另一个视图控制器时,剩余时间仍然存在。

中小时

@interface ViewController : UIViewController {

    IBOutlet UILabel *countdownLabel;
    NSTimer *countdownTimer;
    int secondCount;
}

- (IBAction)start:(id)sender;

计时器代码(单位:m):

-(void) timerRun {

    secondCount = secondCount - 1;
    int hours = (secondCount/ 3600) % 24;
    int minuts = (secondCount / 60) % 60;
    int seconds = secondCount % 60;


    NSString *timerOutput = [NSString stringWithFormat:@"%2d:%.2d:%2d", hours, minuts, seconds];

    countdownLabel.text = timerOutput;

}


-(void) setTimer {

    secondCount = 82800;
    countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];


}


- (IBAction)start:(id)sender {

    [self setTimer];


}

这里是NSUserDefaults的相关代码:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDate *now = [NSDate date];
double countDown = 82800.0; // in seconds, get this from your counter
[userDefaults setObject:now forKey:@"timeAtQuit"];
[userDefaults setDouble:countDown forKey:@"countDown"];
[userDefaults synchronize];


// restore state
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDate *timeAtQuit = [userDefaults objectForKey:@"timeAtQuit"];
double timeSinceQuit = [timeAtQuit timeIntervalSinceNow];
double countDown = timeSinceQuit + [userDefaults doubleForKey:@"countDown"];

谁能告诉我如何将 NSUserDefault 与计时器结合起来,以及将代码放在哪里,以便计时器可以 运行 在退出应用程序或转到另一个视图控制器后

请帮忙

根据您的解释,我了解到即使负责显示时间的视图控制器尚未初始化,您的计时器对象也应该继续工作,因此当应用程序第二次启动时,视图控制器将获得正确的剩余时间来自计时器实例的时间。

因此,我建议您创建一个单独的 class 来跟踪应用程序的状态(通过 NSNotificationCenter class)并处理重新初始化或失效你的定时器对象。

这是描述上述逻辑的概念设计证明:

TimerManager.h

extern NSString * const TimerManagerDidCountDownNotification;

@interface TimerManager
@property (nonatomic, strong, readonly) NSTimer *timer;
@property (nonatomic, assign, readonly) CGFloat remainingTime;

+ (instancetype)sharedManager;
- (void)setCountDown:(CGFloat)countDown override:(BOOL)override;
@end

TimerManager.h

NSString * const TimerManagerDidCountDownNotification = @"TimerManagerDidCountDownNotification";

@interface TimerManager ()
@property (nonatomic, strong, readwrite) NSTimer *timer;
@property (nonatomic, assign, readwrite) CGFloat remainingTime;
@end

@implementation TimerManager
@synthesize remainingTime=_remainingTime;

- (instancetype)init
{
    self = [super init];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];

    return self;
}

+ (instancetype)sharedManager
{
    static TimerManager *sharedManager = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        sharedManager = [[self alloc] init];
    });

    return sharedManager;
}

- (void)didCountDown
{
    if (self.remainingTime > 0.0) {
        CGFloat newRemainingTime = self.remainingTime - 1.0;
        [[NSNotificationCenter defaultCenter] postNotificationName:TimerManagerDidCountDownNotification object:nil userInfo:@{"remainingTime": @(newRemainingTime)}];
        self.remainingTime = newRemainingTime;
    }
    else {
        [_timer invalidate];
        _timer = nil;
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"remaining_time"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

- (CGFloat)remainingTime
{
    return [[NSUserDefaults standardUserDefaults] floatForKey:@"remaining_time"];
}

- (CGFloat)setRemainingTime:(CGFloat)remainingTime
{
   [[NSUserDefaults standardUserDefaults] setFloat:remainingTime forKey:@"remaining_time"];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)setCountDown:(CGFloat)countDown override:(BOOL)override
    if (override || self.remainingTime == 0.0) {
        [_timer invalidate];
        self.remainingTime = countDown;
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(didCountDown) userInfo:nil repeats:YES];
    }
}

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
   if (_timer) {
      [_timer invalidate];
      _timer = nil;
   }       
}

- (void)applicationWillEnterForeground:(NSNotification *)notification
{
   if (!_timer) {
      _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(didCountDown) userInfo:nil repeats:YES];
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

在您的视图控制器 class 中,您可以覆盖 viewDidLoad 并将回调函数 (timerRun:) 注册到通知中心对象,以便从计时器获取剩余时间:

ViewController.m

- (void)viewDidLoad
{
   [super viewDidLoad];

   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(timerRun:) name:TimerManagerDidCountDownNotification object:nil];
}

- (void)timerRun:(NSNotification *)notification 
{
   CGFloat secondCount = [notification[@"remainingTime"] floatValue];
   int hours = (secondCount / 3600) % 24;
   int minuts = (secondCount / 60) % 60;
   int seconds = secondCount % 60;

   NSString *timerOutput = [NSString stringWithFormat:@"%2d:%.2d:%2d", hours, minuts, seconds];

   countdownLabel.text = timerOutput;
}

- (IBAction)start:(id)sender 
{
    [[TimerManager sharedManager setCountDown:82800.0 override:YES];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

您可以使用 application:didFinishLaunchingWithOptions 方法作为起点,以给定的 countdown 值触发计时器。

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // some other initialization logic here...

    [[TimerManager sharedManager] setCountDown:82800.0 override:NO];
    return YES;
}