+[NSTimer scheduledTimerWithTimeInterval:...]
GCD ワーカー スレッドから呼び出しています。GCD ワーカー スレッドは実行ループを実行しません。それがあなたの最初の試みがうまくいかなかった理由です。
を試したとき[[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode]
、GCD ワーカー スレッドからメインの実行ループにメッセージを送信していました。問題NSRunLoop
はスレッドセーフではありません。(これはNSRunLoop Class Referenceに記載されています。)
addTimer:...
代わりに、メッセージをメインの実行ループに送信するときにメイン スレッドで処理されるように、メイン キューにディスパッチする必要があります。
-(void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSTimer *timer = [NSTimer timerWithTimeInterval:0.10
target:self
selector:@selector(action_Timer)
userInfo:nil
repeats:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
});
});
}
現実的には、メインの実行ループでタイマーをスケジュールする場合、バックグラウンド キューでタイマーを作成する理由はありません。メイン キューにディスパッチして、それを作成してスケジュールすることができます。
-(void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"on background queue");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"on main queue");
[NSTimer scheduledTimerWithTimeInterval:0.10
target:self
selector:@selector(action_Timer)
userInfo:nil
repeats:YES];
});
});
}
どちらのソリューションもタイマーをメインの実行ループに追加するため、タイマーのアクションはメイン スレッドで実行されることに注意してください。タイマーのアクションをバックグラウンド キューで実行する場合は、アクションからディスパッチする必要があります。
-(void)action_Timer {
// This is called on the main queue, so dispatch to a background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
LOG("Timer called");
});
}