dispatch_async不使用块

时间:2013-05-28 01:24:14

标签: objective-c grand-central-dispatch dispatch-async

我想使用dispatch_async偶尔从我的Web服务器中提取不断变化的资源(大约每60秒)。

我想使用dispatch_async,但我想给它一个函数名。因为我想让这个功能睡觉并重新做同样的事情。

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

我认为while循环不是一个好主意,所以我想知道什么是最好的方法

2 个答案:

答案 0 :(得分:4)

有几点意见:

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

    @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功能。所有采用块的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 example),或使用推送通知(notifications documents谈论本地通知和推送通知,但对于此应用程序,您正在查看推送通知)。显然,这些都需要更多的服务器开发,但它在架构上更优雅/更有效。

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

答案 1 :(得分:0)

怎么样......

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上的,但您无需担心与它接口直接