iOS NSTimer の実行されない問題#
背景#
このバージョンがリリースされた後、イベントトラッキングデータが急激に減少しました。デバッグの結果、タイマーによるメソッドの実行が行われていないことがわかりましたが、タイマーのメソッド自体は修正されていませんでした。以下がコードです。
- (BOOL)initTimer() {
self.uploadTimer = [NSTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.uploadTimer forMode:NSRunLoopCommonModes];
}
排除#
この handleUpload メソッドがどのようにしても実行されませんが、以前のバージョンでは正常に動作していました。調査した結果、外部の呼び出し箇所に非同期処理が追加されていることがわかりました。具体的には、呼び出し箇所が以下のように変更されました。
dispatch_async(dispatch_get_global_queue(0, 0), ^{
initTimer()
});
これにより、タイマーが起動しなくなりました。
原因#
解決策:サブスレッドで runloop を起動するだけです。
- (BOOL)initTimer() {
self.uploadTimer = [NSTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.uploadTimer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
}
思考#
この問題を通じて、2 つのポイントを学びました。
- タイマーは iOS 開発でよく使用され、多くのブログで注意すべき点が紹介されています。通常はメモリ管理やタイマーの起動に関するものですが、開発中に実際の問題に直面しない限り、自分自身で注意することは十分ではありません。今回の経験を経て、今後は非同期でタイマーを使用する場合には、より注意深くなるでしょう。
- この initTimer メソッドは実際には SDK の初期化メソッドであり、SDK 内部では変更されていませんが、SDK を使用する外部のアプリケーション側で変更が加えられたため、SDK が正常に動作しなくなりました。したがって、SDK を作成する際には、タイマーを使用する場合はスレッドのチェックを行うか、コードを安全に保証する必要があります。第三者の呼び出し元の使用状況を保証することはできないため、自身のコードの正確性を確保する必要があります。