简体   繁体   English

全局队列中的计时器未在iOS中调用

[英]Timer inside global queue is not calling in iOS

-(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 is not being called. 没有调用action_Timer I dont know why. 我不知道为什么。 Do you have any idea? 你有什么主意吗?

You're calling +[NSTimer scheduledTimerWithTimeInterval:...] from a GCD worker thread. 您正在从GCD工作线程调用+[NSTimer scheduledTimerWithTimeInterval:...] GCD worker threads don't run a run loop. GCD工作线程不运行运行循环。 That's why your first try didn't work. 这就是为什么你的第一次尝试不起作用的原因。

When you tried [[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode] , you were sending a message to the main run loop from a GCD worker thread. 当您尝试[[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode] ,您正在从GCD工作线程向主运行循环发送消息。 The problem there is NSRunLoop is not thread-safe. NSRunLoop存在的问题不是线程安全的。 (This is documented in the NSRunLoop Class Reference .) (这在NSRunLoop类参考中有记录 。)

Instead, you need to dispatch back to the main queue so that when you send the addTimer:... message to the main run loop, it's done on the main thread. 相反,您需要调度回主队列,以便在将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];
        });        
    });
}

Realistically, there's no reason to create the timer on the background queue if you're going to schedule it in the main run loop. 实际上,如果您要在主运行循环中安排计时器,则没有理由在后台队列上创建计时器。 You can just dispatch back to the main queue to create and schedule it: 您可以调度回主队列来创建和安排它:

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

Note that both of my solutions add the timer to the main run loop, so the timer's action will run on the main thread. 请注意,我的两个解决方案都将计时器添加到主运行循环中,因此计时器的操作将在主线程上运行。 If you want the timer's action to run on a background queue, you should dispatch to it from the action: 如果您希望计时器的操作在后台队列上运行,您应该从操作中调度它:

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

You have to add the timer to the main run loop for the timer to fire, but first, you should hold reference to to the timer in a private ivar or a property: 您必须将计时器添加到主运行循环以启动计时器,但首先,您应该在私有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");
    });
}

I find easier to get off the main queue in the called method. 我发现在被调用的方法中更容易脱离主队列。 At somepoint, maybe in viewDidUnlod or in dealloc , you will have call [self.myTimer invalidate]; self.myTimer = nil; 在某些点,也许在viewDidUnloddealloc ,你将调用[self.myTimer invalidate]; self.myTimer = nil; [self.myTimer invalidate]; self.myTimer = nil; .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM