1

我想使用 dispatch_async 偶尔从我的网络服务器中提取一个变化的资源(大约每 60 秒)。

我想使用 dispatch_async 但我想给它一个函数名。因为我希望该功能休眠并再次重做相同的事情。

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

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

4

2 回答 2

4

几点观察:

  1. 如果要为分派操作创建计时器,请创建一个dispatch_source_ttype 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 函数都有一个_f采用 C 函数的演绎版(后缀为 )。例如,使用上面的示例,非块再现将如下所示:

    - (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. 如果您更愿意使用 a 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 秒触发一次网络事件,如果您正在异步启动网络活动(通过NSTimer#3 的方法,或者如果您的网络请求本身异步运行),您可能还想要引入一些检查以确保在启动另一个请求之前已完成先前的请求。它不太可能没有,但是您仍然应该检查一下。如果您使用该dispatch_source_create方法并使用同步网络请求,这不是问题(因为在前一个完成之前不会重新触发计时器),但否则,您可能要小心不要最终支持用网络请求排队。

于 2013-05-28T02:23:00.723 回答
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 上的,但你不必担心直接与它交互。

于 2013-05-28T01:49:07.357 回答