2011-11-11 41 views
4

這是我用於iPhone秒錶的代碼。它按預期工作,並在單擊按鈕時停止並繼續。但是,當我點擊「停止」時,計時器不會停止在後臺運行,當我點擊「開始」恢復它時,它將更新時間並跳到它當前的位置而不是恢復從停止的時間。使用NSTimer的秒錶不正確地包含顯示中的暫停時間

如何停止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"; 
} 
+1

您的暫停按鈕調用哪個動作? –

+0

對不起,我的意思是onStopPressed動作,暫停和停止是同一件事 –

回答

11

您對當前顯示的計算總是使用計時器的原始開始時間,因此暫停後的顯示包括計時器暫停的時間間隔。

最簡單的做法是在計時器暫停時存儲另一個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了這麼多,你可能要考慮將它伊娃還是把它放在static存儲在showActivity:,像這樣:

static NSDateFormatter * dateFormatter = nil; 
if(!dateFormatter){ 
    dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"mm:ss.SS"]; 
    [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]]; 
} 
+0

非常感謝,這是一個更有效的方式來做到這一點。我有一個快速的錯誤,希望你能幫助我,我似乎無法'secondsAlreadyRun + = [NSDate timeIntervalSinceDate:startDate];'工作。我需要什麼變量或者還有什麼要做的?謝謝! –

+0

'secondsAlreadyRun'應該是'NSTimeInterval' ivar。 「無法正常工作」是指什麼? –

+0

嗯是的,我有'secondsAlreadyRun'作爲'NSTimeInterval'伊娃,但它返回錯誤消息「無效的操作數到二進制表達式('NSTimeInterval'(又名'雙')和'ID'),並給出警告」類方法「 + timeIntervalSinceDate'not found「。我一定是做錯了,謝謝你的幫助 –

0

您是否在使用ARC?

如果您使用ARC,它看起來像你沒有使用_strong引用。如果你沒有使用ARC,它看起來並沒有保留對定時器的引用。

我將此內容發自手機上,因此可能會漏掉一些內容。

編輯:只是注意到你在其他地方使用版本,所以我會假設沒有ARC。您需要在設置後才能保留定時器,以便稍後訪問它並使其無效。

2

所以,當用戶按下停止,然後重新開始,您不重置開始時間。但是,當您更新標籤時,您將基於從原始開始時間到當前時間的總時間。所以如果你運行定時器10秒鐘,停下來,等待10秒鐘,然後再次啓動,定時器將顯示00:20.00,並從那裏開始再次計數。

你想要做的是每次用戶啓動時鐘時重新設置開始時間,但也要添加所有先前運行的已用時間。或類似的東西。

順便說一下,你現在每次重置時都會漏出開始時間。小錯誤。

編輯:看起來像@喬什卡斯韋爾在想同樣的事情,但他更快地輸入了很多。:)

+0

我想我只是在你之前開始...... :) –

0

您可以使用NSTimeInterval而不是定時器。我有一個功能性代碼來暫停和停止計時器。

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

希望這會有所幫助。謝謝

0

我在Swift中爲定時器程序創建了一個定時器類,其中計數器每秒從設定的時間更新一次。回答說明Swift解決方案和NSTimer函數。

定時器可以停止並重新啓動;它會從停止的地方恢復。代表可以攔截事件以進行開始,停止,重置,結束和第二個事件。只需檢查代碼。

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() } 
    } 
    } 

}