LoginSignup
28
21

More than 5 years have passed since last update.

NSTimer周りの話で、メソッドが呼ばれない現象が起きてハマった

Last updated at Posted at 2015-08-30

こんな問題

今までこんなメソッドを使ってTimeInterval秒ごとにメソッドを呼ぶ処理を書いていました。
NSTimer#scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:

しかし開発が進む中で実装を変える必要が出てきたので、メソッドが呼ばれる契機を変えたのです。
そしたら、selectorに指定していたメソッドが呼ばれなくなるという問題が発生しました。

頭の中は「???」。悪いことはなんにもしてないのに。。。

というわけで調べてみました!

原因

scheduledTimerWithTimeInterval〜メソッド

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(hoge:) userInfo:nil repeats:YES];
NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "hoge:", userInfo: nil, repeats: true);

このメソッドは呼ぶだけでTimerを発火してくれるメソッドです。
ただし、現在のスレッドでTimerを発火するようです。
つまり契機がメインスレッドではないスレッドの時は、そのスレッド上でTimerが回ります。

これが原因でした。。。
呼ぶ契機を変えた時に別スレッドから呼ばれる時があったのです。

しかもメインスレッド上でないとselectorに指定したメソッドを呼んでくれないのですね。
というわけで解決方法。

解決方法

timerWithTimeInterval〜メソッド

NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(hoge:) userInfo:nil repeats:YES];
let timer = NSTimer(timeInterval: 0.1, target: self, selector: "hoge:", userInfo: nil, repeats: true);

このメソッドはTimerの発火までは行いません。
要は発火するスレッドを指定することができます。

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSRunLoop.mainRunLoop().addTimer(timer, forMode:NSRunLoopCommonModes);

こんな感じでどのメソッドから来てもメインスレッドで動かすようにします。
これで直せました。

おわり

指摘や質問があれば、どしどし送ってくださいね〜。

28
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
21