NSTimer没有及时解雇

时间:2012-07-16 14:25:13

标签: objective-c ios networking nstimer nsstream

我正在尝试连接到给定IP地址上的端口。一个问题是当使用不存在的IP地址建立连接时,写命令(如下所示):

NSData * imageRequest = [@"640" dataUsingEncoding: NSUTF8StringEncoding];

int image = [self.outputImageStream write:[imageRequest bytes] maxLength:[imageRequest length]];

响应时间超过75秒。我尝试使用以下方法调用启动计时器来处理此问题:

self.connectionTimeoutTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(respondToTimer:)userInfo:nil repeats:NO];

在我定义的1秒间隔内没有调用它。

有没有办法确保定时器在1秒内触发?

1 个答案:

答案 0 :(得分:2)

这可能会回答您关于NSTimer real-time behavior的问题:

  

计时器不是实时机制;只有当添加了计时器的其中一个运行循环模式正在运行并且能够检查计时器的触发时间是否已经过去时,它才会触发。由于典型的运行循环管理各种输入源,因此定时器的时间间隔的有效分辨率被限制在50-100毫秒的量级。如果在长时间标注期间或在运行循环处于不监视计时器的模式下发生计时器的触发时间,则计时器在下次运行循环检查计时器之前不会触发。因此,计时器可能发射的实际时间可能是计划发射时间之后的一段很长时间。

您没有指定如何安排NSTimer,但如果您为NSRunLoopCommonModes而不是NSRunLoopDefaultModes安排NSTimer,则可能会发现其性能有所改善:

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

如果这不会改善事情,那么你应该寻找更低级别的选择。

特别是,您可以查看CADisplayLink

  

CADisplayLink对象是一个计时器对象,允许您的应用程序将其绘图与显示的刷新率同步。

可以与NSTimer非常相似的方式使用。

CADisplayLink的优势在于它与刷新率相关联,因此它应该在1/60秒的时间间隔内提供非常可靠的行为。

使用CADisplayLink的示例:

CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(respondToTimer)];
[displayLink setFrameInterval:60];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

这将每{60}帧调用respondTimer,即每秒一次。由于您希望只调用一个方法,因此可以使用:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
                           dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                               [self respondToTimer];
                           });

对你来说可能更容易。 (当然,您可以使用该方法的完整实现替换对[self respondToTimer]的调用。)