NSTimer is not fired in time

自作多情 提交于 2019-12-08 09:31:27

问题


I am trying to connect to a port on a given IP Address. The one problem is that when a connection is established with a non existent IP Address the write command (which is as follows):

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

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

It takes over 75 seconds to respond. I try dealing with this by starting a timer with the following method call:

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

It is not called within the 1 second interval I define.

Is there any way to ensure that the timer fires within 1 second?


回答1:


This might answer your question about NSTimer real-time behavior:

A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.

You don't specify how you are scheduling the NSTimer, but you might find some improvements in its performance if you schedule it for NSRunLoopCommonModes instead of NSRunLoopDefaultModes:

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

If this does not improve things, then you should look for lower-level alternatives.

In particular, you might look into CADisplayLink:

A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.

which can be used in a quite similar fashion as NSTimer.

The advantage of CADisplayLink is that it is linked to the refresh rate, so it should give pretty reliable behavior for 1/60 sec time interval.

Example of use of CADisplayLink:

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

This will call respondTimer each 60 refresh frames, i.e., once per second. Since you want your method to be called just one, you could use:

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

and it will be possibly easier for you. (Of course you could replace the call to [self respondToTimer] with the full implementation for that method).



来源:https://stackoverflow.com/questions/11506398/nstimer-is-not-fired-in-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!