【问题标题】:NSTimer and NSUserDefaultsNSTimer 和 NSUserDefaults
【发布时间】:2015-05-02 21:44:34
【问题描述】:

计时器将是 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 与计时器结合起来,以及将代码放在哪里,以便在退出应用程序或转到另一个视图控制器后计时器可以运行

请帮忙

【问题讨论】:

    标签: objective-c nsuserdefaults nstimer countdown


    【解决方案1】:

    根据您的解释,我知道即使您负责显示时间的视图控制器尚未初始化,您的计时器对象也应该继续工作,因此当应用程序第二次启动时,视图控制器将从计时器实例。

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

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

    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];
    }
    

    在您的视图控制器类中,您可以覆盖 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;
    }
    

    【讨论】:

    • 你有没有更简单的方法让标签和按钮上的计数器作为触发器,并能够保存它@ozgur
    • 我相信有更简单的方法,但是最好将应用程序中的不同功能彼此分开,这样您的代码将更具可读性和可理解性。
    • 逻辑基本上是在另一个类中处理定时器相关事件,并通过通知中心通知视图控制器剩余时间变化。
    • 所以我需要为 TimeManager 创建一个类,子类是 NSNotificationCenter? @ozgur
    • 我刚刚在课堂上复制了你的代码,有一些错误,可以发给你看看吗? @ozgur
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 2010-12-05
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    相关资源
    最近更新 更多