今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

iOS NSTimerの実行されない問題

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

これにより、タイマーが起動しなくなりました。

原因#

iOS では、メッセージループの仕組みとして runloop が使用されており、メインスレッドはデフォルトで runloop が起動していますが、サブスレッドにはデフォルトの runloop が存在しないため、サブスレッドでタイマーを起動すると効果がありません。

解決策:サブスレッドで 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 つのポイントを学びました。

  1. タイマーは iOS 開発でよく使用され、多くのブログで注意すべき点が紹介されています。通常はメモリ管理やタイマーの起動に関するものですが、開発中に実際の問題に直面しない限り、自分自身で注意することは十分ではありません。今回の経験を経て、今後は非同期でタイマーを使用する場合には、より注意深くなるでしょう。
  2. この initTimer メソッドは実際には SDK の初期化メソッドであり、SDK 内部では変更されていませんが、SDK を使用する外部のアプリケーション側で変更が加えられたため、SDK が正常に動作しなくなりました。したがって、SDK を作成する際には、タイマーを使用する場合はスレッドのチェックを行うか、コードを安全に保証する必要があります。第三者の呼び出し元の使用状況を保証することはできないため、自身のコードの正確性を確保する必要があります。

参考#

IOS 定時器操作と NSTimer の注意点

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。