2011-11-11 2 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インターフェイスは、1つの引数(タイマー自体)を受け入れるメソッドのためのものであることにも注意してください。それがなければうまくいくようですが、なぜ誘惑の運命ですか?

最後に

、あなたがそれIVARすることを検討かそこらのように、showActivity:staticストレージにそれを置きたいかもしれません、NSDateFormatterそのあまりを使用しているので、:

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

ありがとう、これははるかに効率的な方法です。私はうまくいけばあなたが私を助けることができる1つの迅速なエラーを持っている、私は '秒を取得するように思えます秒agoRready + = [NSDate timeIntervalSinceDate:startDate];'働く。どんな変数が必要なのですか、それ以外に何がありますか?ありがとう! –

+0

'secondsAlreadyRun'は' NSTimeInterval'のivarでなければなりません。 「働かせることができない」とはどういう意味ですか? –

+0

ええ私は 'NSTimeInterval'のivarとして' secondsAlreadyRun'を持っていますが、無効なオペランドをバイナリ式( 'NSTimeInterval'(別名 'double')と 'id')に返し、警告 "class method" + timeIntervalSinceDate 'not found'。私はあなたの助けを借りて何か間違ったことをする必要があります –

0

ARCを使用しているかどうかを確認しますか?

あなたはARCを使用している場合は、_strong参照を使用してアレントのように、それが見えます。 ARCを使用していない場合は、タイマーへの参照が保持されていないと見なします。

携帯からこの投稿を送信していますので、何か不足している可能性があります。

EDITは:ちょうどあなたが他の場所でのリリースを使用していた気づいたので、私は何のARCを負いませんよ。タイマーは、後でそれにアクセスして無効にできるように設定した後に保持する必要があります。

2

ので、ユーザーを押します停止してから再開すると、開始時刻はリセットされません。しかし、ラベルを更新すると、元の開始時刻から現在の時刻までの合計経過時間に基づいてラベルが作成されます。その後、

あなたは10秒のタイマーを実行するのであれば、停止し、10秒待ってから再び起動し、タイマーは00表示されます:20.00をして、そこから再びカウントを開始。あなたが何をしたいか

は、開始時刻にユーザーがクロックを開始し、その後も同様に、すべての以前の実行の経過時間を追加するたびにリセットされます。または類似のもの。

現在、リセットするたびに開始時刻がリークしています。マイナーバグ。

EDIT:@Joshキャスウェルは、同じことを考えていたように見えますが、彼のタイプLOT速いです。:)

+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機能を説明するために回答しました。

タイマーを停止して再起動できます。停止した場所から再開します。イベントは、デリゲートによって開始、停止、リセット、終了、および2番目のイベントをインターセプトできます。ちょうどコードをチェックしてください。

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

} 
関連する問題