How to Wait in Objective-C and Swift
Asked Answered
W

8

49

I want to change my UILabel's text after 2 seconds.

I tried setting my UILabel's text to "A text", and use sleep(2) and finally changing the text to "Another text".

But sleep(2) only freezes the app and "Another text" is set without displaying "A text" for 2 seconds.

How may I display "A text" for 2 seconds and then show "Another text"?

Wowser answered 8/8, 2011 at 14:10 Comment(1)
possible duplicate of Calling sleep(5); and updating text field not workingTautologism
D
44

You can use

[self performSelector:@selector(changeText:) withObject:text afterDelay:2.0];

or if you want to display it periodically, check the NSTimer class.

Dent answered 8/8, 2011 at 14:15 Comment(0)
G
90

I know I am late to this party. But I found people haven't mention thread sleep. If you are using GCD to call that function. You can use :

NSThread sleepForTimeInterval:2.0f];   

to delay the thread for 2 seconds.

[self changeText: @"A text"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  //Here your non-main thread.
  [NSThread sleepForTimeInterval:2.0f];   
  dispatch_async(dispatch_get_main_queue(), ^{
    //Here you returns to main thread.
    [self changeText: @"Another text"];
  });
});

Edit 2 (Feb 2015)

I think the NSTimer is a great solution. My solution just giving another option to achieve the goal of NSTimer.

Please read: How do I use NSTimer?

[NSTimer scheduledTimerWithTimeInterval:2.0
         target:self
         selector:@selector(doSomethingWhenTimeIsUp:)
         userInfo:nil
         repeats:NO];

In the class, you need this method:

- (void) doSomethingWhenTimeIsUp:(NSTimer*)t {
  // YES! Do something here!!
}

Edit 3 (May 2016)

In Swift 2.0, you can use this way:

NSTimer.scheduledTimerWithTimeInterval(2.0, 
                                       target: self, 
                                       selector: "doSomethingWhenTimeIsUp:", 
                                       userInfo: nil, 
                                       repeats: false)

It creates an NSTimer's entity and adds the timer automatically to the NSRunLoop associated with the NSThread in which the timer is created.

Edit 4 (Jun 2016) In Swift 2.2, the way to invoke select is:

#selector(doSomethingWhenTimeIsUp(_:))

So, it is something like:

NSTimer.scheduledTimerWithTimeInterval(2.0,
                                       target: self,
                                       selector: #selector(doSomethingWhenTimeIsUp()),
                                       userInfo: nil,
                                       repeats: false)

Edit 5 (Oct 2016)

In Swift 3, the way to invoke select is:

#selector(doSomethingWhenTimeIsUp)

So, it is something like:

Timer.scheduledTimer(timeInterval: 2.0,
                     target: self,
                     selector: #selector(doSomethingWhenTimeIsUp),
                     userInfo: nil,
                     repeats: false)

Then, the func should looks like this:

@objc private func doSomethingWhenTimeIsUp(){
  // Do something when time is up
}

Edit 6 (May 2018) In Swift 4, we can do as below way.

let delaySeconds = 2.0
DispatchQueue.main.asyncAfter(deadline: .now() + delaySeconds) {
  doSomethingWhenTimeIsUp()
}  

Then, the func should looks like this:

private func doSomethingWhenTimeIsUp(){
  // Do something when time is up
}
Goosander answered 8/8, 2013 at 2:44 Comment(2)
This was useful for me to use in a do-while loop within a dispatch_async. Thanks. +1Mesoglea
Especially for those working closely with threading, this is a much better answer. ++Later
D
44

You can use

[self performSelector:@selector(changeText:) withObject:text afterDelay:2.0];

or if you want to display it periodically, check the NSTimer class.

Dent answered 8/8, 2011 at 14:15 Comment(0)
S
30

Grand Central Dispatch has a helper function dispatch_after() for performing operations after a delay that can be quite helpful. You can specify the amount of time to wait before execution, and the dispatch_queue_t instance to run on. You can use dispatch_get_main_queue() to execute on the main (UI) thread.

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // do something
});

In Swift 3, the above example can be written as:

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    // do something
}
Surefooted answered 8/8, 2013 at 3:7 Comment(0)
A
12

You can use NSTimer, like so -

[NSTimer scheduledTimerWithTimeInterval:0.5 
                                 target:self 
                               selector:@selector(updateLabel:) 
                               userInfo:nil 
                                repeats:YES];

Define another method updateLabel and do the updation there. Define your timeInterval to suite your needs...

Also setting repeats to YES makes sure that this selector is executed every 0.5 seconds (in the above case).

Arrear answered 8/8, 2011 at 14:14 Comment(0)
E
5

You can accomplish this with a timer, e.g.

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(eventToFire:) userInfo:nil repeats:YES]; // Fire every 4 seconds.
   
...

- (void)eventToFire:(NSTimer*)timer {
  // Do Something
}
Estaminet answered 8/8, 2011 at 14:14 Comment(0)
A
2

This is because the view isn't updated until the end of the runloop. Instead of using sleeps try using NSTimer to set a specific time to update the view.

Aloisia answered 8/8, 2011 at 14:14 Comment(0)
G
2

You need to use a timer. Using sleep will halt your entire program. Check NSTimer

Gerber answered 8/8, 2011 at 14:14 Comment(0)
S
0

The follow method is good.

You can replace your

sleep(1);

with

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC));

Singlehandedly answered 28/6, 2019 at 3:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.