dispatch_async without using a block



我想使用dispatch_async偶尔从我的web服务器(大约每60秒)拉一个不断变化的资源。

我想使用dispatch_async,但我想给它一个函数名代替。因为我想让这个函数休眠然后再做同样的事情。

这就是我想做的dispatch_async(self.downloadQueue, @selector(getDataThread:));(这不编译)

我认为while循环不是一个好主意,所以我想知道这个

的最佳方法是什么

几点观察:

  1. 如果你想为调度操作创建一个定时器,创建DISPATCH_SOURCE_TYPE_TIMER类型的dispatch_source_t,例如,定义两个类属性:

    @property (nonatomic, strong) dispatch_queue_t  queue;
    @property (nonatomic, strong) dispatch_source_t timer;
    

    然后创建定时器:

    - (void)createTimer
    {
        self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
        if (self.timer)
        {
            dispatch_source_set_timer(self.timer,
                                      dispatch_walltime(NULL, 0),
                                      60ull * NSEC_PER_SEC,
                                      1ull * NSEC_PER_SEC);
            dispatch_source_set_event_handler(self.timer, ^{
                NSLog(@"doing something");
            });
            dispatch_resume(self.timer);
        }
    }
    

    顺便说一下,像所有重复计时器一样,在viewDidAppear中创建并在viewDidDisappear中删除可能是一种良好的实践:

    - (void)viewDidAppear:(BOOL)animated
    {
        [self createTimer];
    }
    - (void)viewDidDisappear:(BOOL)animated
    {
        dispatch_source_cancel(self.timer);
    }
    
  2. 如果你不想使用块,使用_f等效的任何GCD函数。所有接受block的GCD函数都有一个接受C函数的变体(后缀为_f)。例如,使用上面的示例,非块的呈现看起来像:

    - (void)createTimer
    {
        self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
        if (self.timer)
        {
            dispatch_source_set_timer(self.timer,
                                      dispatch_walltime(NULL, 0),
                                      60ull * NSEC_PER_SEC,
                                      1ull * NSEC_PER_SEC);
            dispatch_source_set_event_handler_f(self.timer, &myTimerHandler);
            dispatch_resume(self.timer);
        }
    }
    void myTimerHandler(void *context)
    {
         NSLog(@"doing something");
    }
    
  3. 如果你更愿意使用NSTimer(它使用Objective-C方法而不是C函数),你可能有这样的属性:

    @property (nonatomic, strong) dispatch_queue_t  queue;
    @property (nonatomic, strong) NSTimer *timer;
    

    然后在视图出现时创建计时器,当它消失时删除它:

    - (void)viewDidAppear:(BOOL)animated
    {
        self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
        self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
    }
    - (void)viewDidDisappear:(BOOL)animated
    {
        [self.timer invalidate];
    }
    - (void)handleTimer:(NSTimer *)timer
    {
        dispatch_async(self.queue, ^{
            NSLog(@"doing something");
        });
    }
    
  4. 就我个人而言,如果你经常检查这个,那么也许拉架构(你每60秒不断拉下数据)可能没有意义。您可以考虑打开服务器的套接字并让服务器在数据更新时通知您(参见Ray Wenderlich的示例),或者使用推送通知(通知文档讨论了本地通知和推送通知,但对于这个应用程序,您将看到推送通知)。显然,这两者都需要更多的服务器开发,但它在架构上更优雅/高效。

  5. 顺便说一下,如果您打算每60秒触发一次网络事件,如果您正在异步启动网络活动(通过#3的NSTimer方法,或者您的网络请求本身是异步运行的),您可能还需要引入一些检查,以确保在启动另一个请求之前,前面的请求已经完成。它不太可能没有,但你还是应该检查一下。如果您使用dispatch_source_create方法并使用同步网络请求,这不是问题(因为直到前一个计时器完成才会重新触发计时器),但否则,您可能要小心,以免最终用网络请求备份队列。

怎么样?

NSTimer *timer = [NSTimer timerWithTimeInterval:60 target:self selector:@selector(getDataThread:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- (void)getDataThread:(id)foo {
    dispatch_async(self.downloadQueue, ^{
       // code you want to run asynchronously
    });
}

似乎你想要一些代码块异步运行…但是你希望它也在一个定时间隔内运行,所以我认为这应该足够了。

如果你想抛弃块和dispatch_async,你可以看看NSOperationQueue,记住NSOperationQueue是建立在GCD上的,但你不需要担心直接与它接口

最新更新