Proper way to delay while allowing the run loop to continue
Asked Answered
A

4

7

I have a need to delay for a certain amount of time and yet allow other things on the same runloop to keep running. I have been using the following code to do this:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];

This seems to do exactly what I want, except that sometimes the function returns immediately without waiting the desired time (1 second).

Can anyone let me know what could cause this? And what is the proper way to wait while allowing the run loop to run?

NOTE: I want to delay in a manner similar to sleep(), such that after the delay I am back in the same execution stream as before.

Aphasic answered 12/10, 2012 at 19:13 Comment(2)
What is it that you want to delay? Have you looked at dispatch_after?Aliaalias
I want to delay the current thread, in a way similar to sleep(), except I want the runloop to continue to run (so other events and stuff can kick in) during that delay time.Aphasic
G
9

You should use GCD and dispatch_after for that. It is much more recent and efficient (and thread-safe and all), and very easy to use.

There is even a code snippet embedded in Xcode, so that if you start typing dispatch_after it will suggest the snippet and if you validate it will write the prepared 2-3 lines for you in your code :)

Code Snippet suggestion by Xcode

int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    <#code to be executed on the main queue after delay#>
});
Gride answered 12/10, 2012 at 19:51 Comment(3)
The method you mention runs a different piece of code on the main queue, what I want to do is basically delay for a period of time and return to the code I was running before. For example if I had a for loop which did a print then wait one second and then repeat. I want the statement to simply 'sleep' for a second and then return back to the for loop which I was running before. Does that make sense?Aphasic
That does and does not make sense. You can do this by making your thread to sleep ([NSThread sleepForTimeinterval:] or usleep()?) but this will make an active pause, which is not recommanded in proper OOP programming patterns. And if you execute your for loop on the main runloop, of course it will "freeze" your application. So that's probably bad design.Gride
The solution I see if you really want to execute N iterations each separated by 1 second is to for(int i=0;i<N;++i) { dispatch_after(N seconds, mainQueue, ^{ ... }); } so that your loop will schedule N dispatch_after calls, the N-th iteration being scheduled N seconds after the current time. Or to perform your iteration with anything other than a traditional for loop, like recursive code that calls dispatch_after at the end of its iteration to schedule the next iteration 1 second later.Gride
H
1

Use an NSTimer to fire off a call to some method after a certain delay.

Histogenesis answered 12/10, 2012 at 19:18 Comment(0)
C
1

Have you tried performSelector:withObject:afterDelay:?

From the Apple documentation

Invokes a method of the receiver on the current thread using the default mode after a delay.

Charbonneau answered 12/10, 2012 at 21:4 Comment(0)
I
0

I had a similar issue and this is my solution. Hope it works for others as well.

__block bool dispatched = false;
while ( put your loop condition here )
{
    if (dispatched)
    {
        // We want to relinquish control if we are already dispatched on this iteration.
        [ [ NSRunLoop currentRunLoop ] runMode: NSDefaultRunLoopMode beforeDate:[ NSDate date ] ];
        continue;
    }

    // mark that a dispatch is being scheduled
    dispatched = true;

    int64_t delayInNanoSeconds = (int64_t) (0.1 * (float) NSEC_PER_SEC);
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, delayInNanoSeconds);

    dispatch_after(delayTime, dispatch_get_main_queue(), ^() {
       // Do your loop stuff here
       // and now ready for the next dispatch
       dispatched = false;
    } );
}  // end of while 
Izard answered 14/12, 2015 at 4:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.