6
-(void)viewDidLoad{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSTimer scheduledTimerWithTimeInterval:0.10 
                                         target:self 
                                       selector:@selector(action_Timer) 
                                       userInfo:nil 
                                        repeats:YES];
        }
    );
}

-(void)action_Timer{
    LOG("Timer called");
}

action_Timerは呼び出されていません。どうしてか分かりません。何か考えはありますか?

4

2 に答える 2

18

+[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");
    });
}
于 2013-01-28T20:08:49.057 に答える
1

タイマーを起動するには、タイマーをメインの実行ループに追加する必要がありますが、最初に、プライベート ivar またはプロパティでタイマーへの参照を保持する必要があります。

-(void)viewDidLoad{
        // on the main queue
        self.mytimer = [NSTimer scheduledTimerWithTimeInterval:0.10 
                                                        target:self 
                                                      selector:@selector(action_Timer) 
                                                      userInfo:nil 
                                                        repeats:YES];
        [[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];
}

-(void)action_Timer{
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        LOG("Timer called");
    });
}

呼び出されたメソッドでメイン キューから降りる方が簡単だと思います。ある時点で、おそらく inviewDidUnlodまたは in でdealloc、 call が発生します[self.myTimer invalidate]; self.myTimer = nil;

于 2013-01-28T19:55:59.327 に答える