web-dev-qa-db-ja.com

NSTimerをプログラムで一時停止するにはどうすればよいですか?

NSTimerを使用して、OpenGLベースのiPhoneアプリでレンダリングを行います。ポップアップしてユーザー入力を要求するモーダルダイアログボックスがあります。ユーザーが入力を提供している間、「一時停止」したい、つまり次のようにしたい:

[myNSTimer pause];

私は次のようなことをしているので、この構文を使用しています:

[myNSTimer invalidate];

停止したいとき。

NSTimerをプログラムで一時停止するにはどうすればよいですか?

42
MrDatabase

ここから:

http://discussions.Apple.com/thread.jspa?threadID=1811475&tstart=75

「タイマーが開始してから経過した時間を保存できます...タイマーが開始するとNSDate変数に日付が保存されます。その後、ユーザーが切り替えると... NSDateクラスのtimeIntervalSinceNowメソッドを使用して、時間が経過しました...これはtimeIntervalSinceNowに負の値を与えることに注意してください。ユーザーが戻るとき、適切なタイマーを設定するためにその値を使用します。

タイマーを一時停止して再起動する方法はないと思います。私は同様の状況に直面しました。 」

22
BobbyShaftoe

kapesoftware の答えのマイナーな修正を更新することを考えました:

NSDate *pauseStart, *previousFireDate;

-(void) pauseTimer:(NSTimer *)timer { 

    pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];

    previousFireDate = [[timer fireDate] retain];

    [timer setFireDate:[NSDate distantFuture]];
}

-(void) resumeTimer:(NSTimer *)timer {

    float pauseTime = -1*[pauseStart timeIntervalSinceNow];

    [timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];

    [pauseStart release];

    [previousFireDate release];
}
35
Thiru

NSTimerの発火日を変数に保存し、発火日をINFINITYに設定することでこれを達成しました。

一時停止するとき:

pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];
previousFiringDate = [timer firingDate];
[timer setFiringDate:INFINITY]

一時停止を解除すると、タイマーが一時停止されていた時間を前の発砲日まで追加します。

float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];

これにより、タイマーの無効化と再初期化を心配するよりもずっと簡単になりました。私はタイマーをたくさん持っていたので、それらをすべて配列に入れて、すべてのタイマーにこれを行いました。 NSTimerをサブクラス化して、そのタイマーに関連付けられたpreviousFiringDateを保持します。

これは、BOOLが設定されている場合にアクションが実行されないように、一時停止されているかどうかのBOOLを使用するよりも優れていました。これは、一時停止する前に何かが発生しようとしていた場合、それがスキップされたため、一時停止を解除した後は発生しないためです。

12
kapesoftware

私がそれをなんとかしてやった最も簡単な方法は次のようなものでした:

-(void) timerToggle{
    if (theTimer == nil) {
        float theInterval = 1.0/30.0;
        theTimer = [NSTimer scheduledTimerWithTimeInterval:theInterval target:self selector:@selector(animateBall:) userInfo:nil repeats:YES];
    } else {
        [theTimer invalidate];
        theTimer = nil;
    }
}
8
Riley

私の場合、変数「seconds」と別の「timerIsEnabled」がありました。タイマーを一時停止したいときは、timerIsEnabledをfalseにしました。 seconds変数はtimerIsEnabledがtrueの場合にのみインクリメントされるため、問題を修正しました。お役に立てれば。

8
Oscar Olim

一時停止および再開機能を許可するNSTimerのカテゴリは次のとおりです。

ヘッダ:

#import <Foundation/Foundation.h>

@interface NSTimer (CVPausable)

- (void)pauseOrResume;
- (BOOL)isPaused;

@end

実装:

#import "NSTimer+CVPausable.h"
#import <objc/runtime.h>

@interface NSTimer (CVPausablePrivate)

@property (nonatomic) NSNumber *timeDeltaNumber;

@end

@implementation NSTimer (CVPausablePrivate)

static void *AssociationKey;

- (NSNumber *)timeDeltaNumber
{
    return objc_getAssociatedObject(self, AssociationKey);
}

- (void)setTimeDeltaNumber:(NSNumber *)timeDeltaNumber
{
    objc_setAssociatedObject(self, AssociationKey, timeDeltaNumber, OBJC_ASSOCIATION_RETAIN);
}

@end


@implementation NSTimer (CVPausable)

- (void)pauseOrResume
{
    if ([self isPaused]) {
        self.fireDate = [[NSDate date] dateByAddingTimeInterval:[self.timeDeltaNumber doubleValue]];
        self.timeDeltaNumber = nil;
    }
    else {
        NSTimeInterval interval = [[self fireDate] timeIntervalSinceNow];
        self.timeDeltaNumber = @(interval);
        self.fireDate = [NSDate distantFuture];
    }
}

- (BOOL)isPaused
{
    return (self.timeDeltaNumber != nil);
}

@end
5
Carl Veazey

古い質問ですが、OPが探しているものを正確に達成するために軽量のユーティリティクラスを作成しました。

https://github.com/codeslaw/CSPausibleTimer

繰り返しタイマーもサポートしています。お役に立てば幸いです!

2
Chris

@Thiruと@kapesoftwareの回答に基づいて、関連オブジェクトを使用してNSTimerでObjective-Cカテゴリを作成し、タイマーを一時停止および再開しました。

#import <objc/runtime.h>

@interface NSTimer (PausableTimer)

@property (nonatomic, retain) NSDate *pausedDate;

@property (nonatomic, retain) NSDate *nextFireDate;

-(void)pause;

-(void)resume;

@end

...

@implementation NSTimer (PausableTimer)

static char * kPausedDate = "pausedDate";
static char * kNextFireDate = "nextFireDate";

@dynamic pausedDate;
@dynamic nextFireDate;

-(void)pause {

  self.pausedDate = [NSDate date];

  self.nextFireDate = [self fireDate];

  [self setFireDate:[NSDate distantFuture]];
}

-(void)resume
{
  float pauseTime = -1*[self.pausedDate timeIntervalSinceNow];

  [self setFireDate:[self.nextFireDate initWithTimeInterval:pauseTime sinceDate:self.nextFireDate]];
}

- (void)setPausedDate:(NSDate *)pausedDate
{
  objc_setAssociatedObject(self, kPausedDate, pausedDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSDate *)pausedDate
{
  return objc_getAssociatedObject(self, kPausedDate);
}

- (void)setNextFireDate:(NSDate *)nextFireDate
{
  objc_setAssociatedObject(self, kNextFireDate, nextFireDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSDate *)nextFireDate
{
  return objc_getAssociatedObject(self, kNextFireDate);
}

それは物事を整頓し、タイマーを一時停止して再開するためにインスタンス変数やプロパティを作成する必要がないことを意味します。

2
Toby

NSTimerでカテゴリを自由に再利用してください:

https://github.com/keeshux/ios-components/tree/master/Components/Categories/NSTimer%2BPause

1
keeshux

発射時間間隔が許容範囲内であれば、CADisplayLinkの代わりにNSTimerを使用できます。 CADisplayLinkサポート-pause

displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(fireMethod:)];
displayLink.frameInterval = approximateVaue;//CADisplayLink's frame rate is 60 fps.
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

//pause
[displayLink pause];
0
ooOlly

上記のようにNSTimerを一時停止することはできません。したがって、キャプチャする時間は、タイマーの発火日に依存しないようにする必要があります。ここに私の最も簡単な解決策があります:

タイマーを作成するとき、開始ユニット時間を次のように初期化します。

self.startDate=[NSDate date];
self.timeElapsedInterval=[[NSDate date] timeIntervalSinceDate:self.startDate];//This ``will be 0 //second at the start of the timer.``     

myTimer= [NSTimer scheduledTimerWithTimeInterval:1.0 target:self `selector:@selector(updateTimer) userInfo:nil repeats:YES];

`更新タイマーメソッド:

  NSTimeInterval unitTime=1;
-(void) updateTimer
 {
 if(self.timerPaused)
       {
           //Do nothing as timer is paused
       }
 else{
     self.timerElapsedInterval=timerElapsedInterval+unitInterval;
    //Then do your thing update the visual timer texfield or something.
    }

 }
0
Masud alam

まあ、私はこれをタイマーの一時停止を実装する最良の方法だと思います。静的変数を使用して、一時停止と再開を切り替えます。一時停止では、タイマーを無効にしてnilに設定し、再開セクションでは、開始された元のコードを使用してタイマーをリセットします。

次のコードは、一時停止ボタンのクリックに対する応答に対して機能します。

-(IBAction)Pause:(id)sender
{
    static BOOL *PauseToggle;
    if(!PauseToggle)
    {
        [timer invalidate];
        timer = nil;
        PauseToggle = (BOOL *) YES;
    }
    else
    {
        timer = [NSTimer scheduledTimerWithTimeInterval:0.04 target:self selector:@selector(HeliMove) userInfo:nil repeats:YES];
        PauseToggle = (BOOL *) NO;
    }
}
0
divyenduz

以下のコードはスクロールビューで使用するためのもので、コンテンツを定期的に表示し、完了時に前に戻りますが、一時停止/再起動ボタンには同じロジックを使用できます。

タイマーはロード時に起動し(initiateFeatureTimer)、ユーザーインタラクションのために一時停止し(メソッドのドラッグを開始します)、ユーザーは好きなだけコンテンツを見ることができます。ユーザーが指を離すと(ドラッグが終了します)、featurePausedブール値がリセットされますが、少し遅れて追加するオプションもあります。

このように、スクローラーは指を離してもすぐには動きませんが、ユーザーにより反応します。

//set vars, fire first method on load.
featureDelay = 8; //int
featureInt = featureDelay-1; //int
featurePaused = false; //boolean

-(void)initiateFeatureTimer {
    featureTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(moveFeatureScroller) userInfo:nil repeats:true];
    [featureTimer fire];
}
 -(void)moveFeatureScroller {

    if (!featurePaused){ //check boolean
        featureInt++;

         if (featureInt == featureDelay){
             featureInt = 0; //reset the feature int

            /*//scroll logic
            int nextPage = (featurePage + 1) * w;
            if (featurePage == features.count-1){ nextPage = 0; }
            [featureScroller setContentOffset:CGPointMake(nextPage, 0)]; */          
         }
      }
}

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    featurePaused = true; //pause the timer
}
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    featurePaused = false; //restart the timer
    featureInt = -3; //if you want to add an additional delay
}
0
Johnny Rockex

シンプルなSwift一時停止/再生タイマー。

https://github.com/AnthonyUccello/Swift-Pausable-Timer/blob/master/Timer.Swift

0
Aggressor