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;
}
计时器将是 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;
}