我想使用dispatch_async偶尔从我的web服务器(大约每60秒)拉一个不断变化的资源。
我想使用dispatch_async,但我想给它一个函数名代替。因为我想让这个函数休眠然后再做同样的事情。
这就是我想做的dispatch_async(self.downloadQueue, @selector(getDataThread:));
(这不编译)
我认为while循环不是一个好主意,所以我想知道这个
几点观察:
如果你想为调度操作创建一个定时器,创建
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); }
如果你不想使用块,使用
_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"); }
如果你更愿意使用
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"); }); }
就我个人而言,如果你经常检查这个,那么也许拉架构(你每60秒不断拉下数据)可能没有意义。您可以考虑打开服务器的套接字并让服务器在数据更新时通知您(参见Ray Wenderlich的示例),或者使用推送通知(通知文档讨论了本地通知和推送通知,但对于这个应用程序,您将看到推送通知)。显然,这两者都需要更多的服务器开发,但它在架构上更优雅/高效。
顺便说一下,如果您打算每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上的,但你不需要担心直接与它接口