web-dev-qa-db-ja.com

NSTimerの使い方は?

どのようにNSTimerを使うのですか?誰もが私に一歩一歩指示を与えることができますか?

345
lab12

まず、Cocoa/CFのドキュメントに注意を向けたいと思います(これは、常に素晴らしい最初の呼び出しです)。 Appleドキュメントの各リファレンス記事の上部に「Companion Guides」と呼ばれるセクションがあり、ドキュメント化されているトピックのガイド(存在する場合)がリストされています。たとえば、NSTimerの場合、 ドキュメント には2つのコンパニオンガイドがリストされます。

状況については、タイマープログラミングトピックの記事が最も役立つと思われます。スレッドトピックは関連していますが、文書化されているクラスに最も直接関連しているわけではありません。タイマープログラミングトピックの記事を見ると、2つの部分に分かれています。

  • タイマー
  • タイマーを使用する

この形式をとる記事の場合、クラスの概要とその使用目的がよくあり、次にhowのサンプルコードがあります。この場合は、タイマーの使用」セクション。 「タイマーの作成とスケジューリング」、「タイマーの停止」、「メモリ管理」のセクションがあります。この記事から、スケジュールされた非繰り返しタイマーの作成は次のようにできます。

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

これにより、2.0秒後に起動されるタイマーが作成され、selfインスタンスへのポインターである1つの引数を使用して、NSTimertargetMethod:が呼び出されます。

その後、メソッドをさらに詳しく調べたい場合は、ドキュメントを参照して詳細を確認できますが、コードに関する説明もあります。

繰り返されるタイマーを停止する場合(または、起動する前に非繰り返しタイマーを停止する場合)、作成されたNSTimerインスタンスへのポインターを保持する必要があります。多くの場合、これは別のメソッドで参照できるようにインスタンス変数である必要があります。その後、invalidateインスタンスでNSTimerを呼び出すことができます。

[myTimer invalidate];
myTimer = nil;

インスタンス変数をnilアウトすることもお勧めです(たとえば、タイマーを無効にするメソッドが複数回呼び出され、インスタンス変数がnilに設定されておらず、NSTimerインスタンスが割り当て解除された場合、例外をスローします) 。

また、記事の下部にあるメモリ管理のポイントにも注意してください。

実行ループはタイマーを維持するため、メモリ管理の観点から、通常、スケジュールした後にタイマーへの参照を保持する必要はありません。メソッドとしてセレクターを指定すると、タイマーが引数として渡されるため、そのメソッド内で適切な場合に繰り返しタイマーを無効にできます。ただし、多くの状況では、タイマーを無効にするオプションも必要です。おそらく、タイマーが開始する前であってもです。 この場合、タイマーへの参照を保持する必要があるため、適切なときに無効化メッセージを送信できます。スケジュールされていないタイマー(「スケジュールされていないタイマー」を参照)を作成する場合、使用する前に割り当てが解除されないように、タイマーへの強い参照を保持する必要があります(参照カウント環境で保持します)。

617
Alex Rozanski

タイマーを使用する方法はいくつかあります。

1) スケジュールタイマーとセレクタを使用

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • 繰り返しをNOに設定すると、タイマーはセレクタを実行する前に2秒間待機し、その後停止します。
  • repeat:YESの場合、タイマーは直ちに開始され、2秒ごとにセレクターの呼び出しを繰り返します。
  • タイマーを停止するには、タイマーの-invalidateメソッドを呼び出します。[t invalidate];

ちなみに、指定した時間が経過しても繰り返してセレクタを呼び出さないタイマーを使用する代わりに、次のような単純なステートメントを使用できます。

[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];

これは上記のサンプルコードと同じ効果があります。しかし、セレクタをn回ごとに呼び出す場合は、タイマーを繰り返し使用します。

2) セルフスケジュールタイマー

NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
                              interval: 1
                              target: self
                              selector:@selector(onTick:)
                              userInfo:nil repeats:YES];

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
  • これはあなたが指定したカスタム日付(この場合は1分後)に開始するタイマーを作成し、1秒ごとに繰り返します。

3) 予定外のタイマーと呼び出しの使用

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
                      invocation:inv 
                      repeats:YES];

そしてその後、あなたはこのように必要なときはいつでも手動でタイマーをスタートさせます。

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];



そして注として、onTick:メソッドは次のようになります。

-(void)onTick:(NSTimer *)timer {
   //do smth
}
332
Woofy

このようなもの:

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];
59
ennuikiller
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}
5
Mohit
#import "MyViewController.h"

@interface MyViewController ()

@property (strong, nonatomic) NSTimer *timer;

@end

@implementation MyViewController

double timerInterval = 1.0f;

- (NSTimer *) timer {
    if (!_timer) {
        _timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
    }
    return _timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

-(void)onTick:(NSTimer*)timer
{
    NSLog(@"Tick...");
}

@end
5
Dan

答えはここに次の時間にある特定の時刻タイマーが抜けています:

NSCalendarUnit allUnits = NSCalendarUnitYear   | NSCalendarUnitMonth |
                          NSCalendarUnitDay    | NSCalendarUnitHour  |
                          NSCalendarUnitMinute | NSCalendarUnitSecond;

NSCalendar *calendar = [[ NSCalendar alloc]  
                          initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *weekdayComponents = [calendar components: allUnits 
                                                  fromDate: [ NSDate date ] ];

[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];

NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];

refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
                                          interval: 0.0
                                            target: self
                                          selector: @selector( doRefresh )
                                          userInfo: nil repeats: NO ];

[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];

もちろん、 "doRefresh"をクラスの希望するメソッドに置き換えてください。

カレンダオブジェクトを一度作成して、allUnitsを効率的にするためにstaticにします。

時間コンポーネントに1を追加することはちょうどうまく働きます、真夜中テストの必要はありません( link

2
gjpc