这是我的iPhone秒表代码。它按预期工作,并在单击按钮时停止和恢复。
但是,当我点击"停止"时,计时器不会在后台停止运行,当我点击"开始"恢复它时,它会更新时间并跳到当前位置,而不是从停止时间恢复。
如何停止NSTimer
?是什么导致了这种情况的发生?
@implementation FirstViewController;
@synthesize stopWatchLabel;
NSDate *startDate;
NSTimer *stopWatchTimer;
int touchCount;
-(void)showActivity {
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"mm:ss.SS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
[dateFormatter release];
}
- (IBAction)onStartPressed:(id)sender {
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1/10 target:self selector:@selector(showActivity) userInfo:nil repeats:YES];
touchCount += 1;
if (touchCount > 1)
{
[stopWatchTimer fire];
}
else
{
startDate = [[NSDate date]retain];
[stopWatchTimer fire];
}
}
- (IBAction)onStopPressed:(id)sender {
[stopWatchTimer invalidate];
stopWatchTimer = nil;
[self showActivity];
}
- (IBAction)reset:(id)sender; {
touchCount = 0;
stopWatchLabel.text = @"00:00.00";
}
你对当前显示的计算总是使用计时器的原始开始时间,因此暂停后的显示包括计时器暂停的时间间隔。
最简单的方法是在计时器暂停时存储另一个NSTimeInterval
,例如secondsAlreadyRun
,并将其添加到恢复时计算的时间间隔中。每次计时器开始计数时,您都需要更新计时器的startDate
。在reset:
中,您还可以清除secondsAlreadyRun
间隔。
-(void)showActivity:(NSTimer *)tim {
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
// Add the saved interval
timeInterval += secondsAlreadyRun;
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"mm:ss.SS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
[dateFormatter release];
}
- (IBAction)onStartPressed:(id)sender {
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1/10
target:self
selector:@selector(showActivity:)
userInfo:nil
repeats:YES];
// Save the new start date every time
startDate = [[NSDate alloc] init]; // equivalent to [[NSDate date] retain];
[stopWatchTimer fire];
}
- (IBAction)onStopPressed:(id)sender {
// _Increment_ secondsAlreadyRun to allow for multiple pauses and restarts
secondsAlreadyRun += [[NSDate date] timeIntervalSinceDate:startDate];
[stopWatchTimer invalidate];
stopWatchTimer = nil;
[startDate release];
[self showActivity];
}
- (IBAction)reset:(id)sender; {
secondsAlreadyRun = 0;
stopWatchLabel.text = @"00:00.00";
}
别忘了在合适的地方释放startDate
!还要记住,记录的NSTimer
接口是为了让您给它的方法接受一个参数,该参数将是计时器本身。似乎没有这个也可以,但为什么要冒险呢?
最后,因为你经常使用NSDateFormatter
,你可能想考虑把它变成一个ivar,或者把它放在showActivity:
的static
存储中,像这样:
static NSDateFormatter * dateFormatter = nil;
if( !dateFormatter ){
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"mm:ss.SS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
}
所以,当用户按下停止键,然后重新开始时,您没有重置开始时间。但是,当您更新标签时,您将基于从原始开始时间到当前时间的总经过时间。
所以如果你运行计时器10秒,停止,等待10秒,然后重新开始,计时器将显示00:20.00,并从那里重新开始计数。
您要做的是在每次用户启动时钟时重置开始时间,但随后也添加所有先前运行的经过时间。或者类似的。
顺便说一句,你现在每次重置都在泄漏启动时间。小错误。
编辑:看起来@Josh Caswell也在想同样的事情,但是他打字快多了。:)
您是否使用ARC ?
如果你正在使用ARC,看起来你没有使用_strong引用。如果你不使用ARC,它不会看到你保留了对计时器的引用。
我是从手机上发布的,所以可能会遗漏一些东西。
编辑:刚刚注意到你在其他地方使用了release,所以我假设没有ARC。您需要在设置计时器之后保留它,以便以后能够访问它并使其失效。
可以使用NSTimeInterval代替timer。我有一个功能代码来暂停和停止计时器。
@interface PerformBenchmarksViewController () {
int currMinute;
int currSecond;
int currHour;
int mins;
NSDate *startDate;
NSTimeInterval secondsAlreadyRun;
}
@end
- (void)viewDidLoad
{
[super viewDidLoad];
running = false;
}
- (IBAction)StartTimer:(id)sender {
if(running == false) {
//start timer
running = true;
startDate = [[NSDate alloc] init];
startTime = [NSDate timeIntervalSinceReferenceDate];
[sender setTitle:@"Pause" forState:UIControlStateNormal];
[self updateTime];
}
else {
//pause timer
secondsAlreadyRun += [[NSDate date] timeIntervalSinceDate:startDate];
startDate = [[NSDate alloc] init];
[sender setTitle:@"Start" forState:UIControlStateNormal];
running = false;
}
}
- (void)updateTime {
if(running == false) return;
//calculate elapsed time
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval elapsed = secondsAlreadyRun + currentTime - startTime;
// extract out the minutes, seconds, and hours of seconds from elapsed time:
int hours = (int)(mins / 60.0);
elapsed -= hours * 60;
mins = (int)(elapsed / 60.0);
elapsed -= mins * 60;
int secs = (int) (elapsed);
//update our lable using the format of 00:00:00
timerLabel.text = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, mins, secs];
//call uptadeTime again after 1 second
[self performSelector:@selector(updateTime) withObject:self afterDelay:1];
}
希望这将帮助。由于
我在Swift中为计时器程序创建的一个计时器类,其中计时器从设定的时间开始每秒更新一次。答:说明Swift解决方案和NSTimer函数
定时器可以停止和重新启动;它会从停止的地方重新开始。事件可以被委托拦截为start, stop, reset, end和second事件。检查一下代码。
import Foundation
protocol TimerDelegate {
func didStart()
func didStop()
func didReset()
func didEnd()
func updateSecond(timeToGo: NSTimeInterval)
}
// Inherit from NSObject to workaround Selector bug
class Timer : NSObject {
var delegate: TimerDelegate?
var defaultDuration: NSTimeInterval?
var isRunning: Bool {
get {
return self.timer != nil && timer!.valid
}
}
private var secondsToGo: NSTimeInterval = 0
private var timer: NSTimer?
init(defaultDuration: NSTimeInterval, delegate: TimerDelegate? = nil) {
self.defaultDuration = defaultDuration
self.delegate = delegate
super.init()
}
func start() {
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTimer", userInfo: nil, repeats: true)
self.timer!.tolerance = 0.05
if delegate != nil { delegate!.didStart() }
}
func stop () {
self.timer?.invalidate()
self.timer = nil
if delegate != nil { delegate!.didStop() }
}
func reset() {
self.secondsToGo = self.defaultDuration!
if delegate != nil { delegate!.didReset() }
}
func updateTimer() {
--self.secondsToGo
if delegate != nil { delegate!.updateSecond(self.secondsToGo) }
if self.secondsToGo == 0 {
self.stop()
if delegate != nil { delegate!.didEnd() }
}
}
}