gpt4 book ai didi

ios - 在全局队列中停止 NSRunLoop

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:59:38 26 4
gpt4 key购买 nike

我刚刚在我的 ViewController 中使用 NSRunLoopNSTimer 创建了一个带计时器的后台任务:

- (void)runBackgroundTask: (int) time{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startTrackingBg) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}

调用一个函数来验证 token 的有效性等。是否可以从函数内部结束这个循环?例如:

-(void)startTrackingBg
{
if(TOKEN IS NOT VALID)
{
STOP_THREAD;
dispatch_sync(dispatch_get_main_queue(), ^{
[self alertStatus:@"Session Lost!" :@"Error!"];
[self popToLogin];
});
}
}

最佳答案

几个想法:

  1. 如果您查看run 的文档,它们会显示解决您问题的模式:

    If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.

    Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. OS X can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.

    If you want the run loop to terminate, you shouldn't use this method. Instead, use one of the other run methods and also check other arbitrary conditions of your own, in a loop. A simple example would be:

    BOOL shouldKeepRunning = YES;        // global
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

    where shouldKeepRunning is set to NO somewhere else in the program.

  2. 话虽如此,如果我要启动另一个线程,我不会用完其中一个全局工作线程,而只是实例化我自己的 NSThread

  3. 更重要的是,根据您在其他线程中尝试执行的操作,通常还有比建立您自己的运行循环更好的其他模式。

    例如,如果我想让计时器在另一个队列中运行某些东西,我会改用调度计时器:

    @property (nonatomic, strong) dispatch_source_t timer;

    然后实例化并启动调度计时器源以在指定的 GCD 队列上运行:

    dispatch_queue_t queue = dispatch_queue_create("com.domain.app.polltimer", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), kPollFrequencySeconds * NSEC_PER_SEC, 1ull * NSEC_PER_SEC);

    dispatch_source_set_event_handler(self.timer, ^{
    <#code to be run upon timer event#>
    });

    dispatch_resume(self.timer);

    或者,如果你想使用 NSTimer,只需将它安排在主运行循环上,然后让它调用的方法将耗时任务分派(dispatch)到后台队列中。但是,无论哪种方式,我都会避免增加第二个运行循环的开销。

  4. 已经向您展示了在后台线程中使用计时器的更好方法,现在您描述了意图(轮询服务器),我实际上建议您完全不要使用计时器。当您希望以固定的时间间隔启动某些操作时,计时器很有用。但在这种情况下,您可能希望在上一个请求完成 一定时间后发起下一个服务器请求。因此,在上一个请求的完成 block 中,您可以执行如下操作:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20.0 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    <#code to initiate next request#>
    });
  5. 此外,我个人希望确保轮询您的服务器有一个非常令人信服的理由。轮询在直觉上总是那么吸引人和合乎逻辑,但它是对用户电池、CPU 和数据计划的过度使用。在您需要客户端快速响应服务器变化的情况下,通常有更好的架构(套接字、推送通知等)。

关于ios - 在全局队列中停止 NSRunLoop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26649927/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com