我的要求是我想调用API每6秒从我的服务器请求一些新信息,所以我编写了如下代码:
MyBackgroundThread(){
while(self.isStop){
[self callMyAPI];
[NSThread sleepfortimeinterval : 6 ];
}
}
但我今天发现Foundation库提供了一种编写运行循环的方法。所以我可以重写我的代码如下:
MyBackgroundThread(){
NSTimer *timer = [NSTimer timerWithTimeInterval:6 target:self selector:@selector(callMyAPI) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer release];
while (! self.isCancelled) {
BOOL ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
但是,我不知道这些是比我原来的更好的工作方式吗?如果是,为什么?如何在这两种方式之间测试效率(或其他属性?)的差异?
谢谢!
答案 0 :(得分:3)
我认为通常不需要为计时器创建新的运行循环。我建议采用以下两种方法之一:
在主运行循环上安排NSTimer
,但让被调用的方法然后将请求分派到后台队列。
创建计划在指定的后台调度队列上运行的调度计时器。为此,请创建调度计时器属性:
@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);
有时候创建一个新的运行循环很有用,但在这个简单的场景中似乎没有必要。
话虽如此,使用定时器每六秒启动一次网络可能没有意义。相反,您可能希望在前一个完成后六秒钟开始下一个请求。由于各种原因,您的服务器可能无法在六秒内响应,并且您不需要希望在这些场景中建立并发请求(如果您的请求以异步方式运行,可能会发生这种情况)。
所以,我倾向于callMyAPI
的完成块做一些简单的事情:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), queue, ^{
<#code to issue next request#>
});
这完全不需要定时器(和自定义运行循环)。
最后,如果您确实需要检测具有该频率的系统更改,则可能表明服务器架构非常不同。例如,如果您每六秒轮询一次以查看服务器上是否有更改,则可以考虑使用基于套接字的实现或使用推送通知。在这两种方法中,服务器将告知客户端应用程序何时发生重大事件,而不是应用程序表现得像汽车后座中的Bart Simpson,不断询问&#34;我们还在那里吗?&#34 ;
适当的体系结构可能是服务器数据可能变化的频率以及客户端应用程序要求的函数。