CocoaCoder
CocoaCoder

Reputation: 29

How can I use an NSTimer (or other) to make events happen after a certain time in Cocoa?

I am using Xcode to create a Cocoa app for Mac OSX written in Objective-C.

Here is my code:

-(IBAction)clickToLaunchAppButtonClicked:(id)sender; {
//I want to hide the click to load app button
[clickToLoadButton setEnabled:NO];
[clickToLoadButton setHidden:YES];

//***I want to make the app wait for 1 second (This is where I'm stuck!)***

//I want to show the loading label
[loadingLabel setEnabled:YES];
[loadingLabel setHidden:NO];

//I want to show the loading progress bar and initialize it
[loadingProgressBar setHidden:NO];
[loadingProgressBar startAnimation:self];

//***I want to make the app wait for 3 seconds (Again, I don't know how to do this!)***

//I want to stop the loading progress bar animation
[loadingProgressBar stopAnimation:self];

//I want to hide the loading progress bar and loading label
[loadingLabel setHidden:YES];
[loadingLabel setEnabled:NO];
[loadingLabel setHidden:YES];
}

How can I make the app wait/pause for a few seconds? I tried the wait(), delay() or pause() functions, but they freeze the app, which is not what I want. Should I use an NSTimer? If so, please give me a simple way to implement it.

Upvotes: 1

Views: 997

Answers (2)

Abhi Beckert
Abhi Beckert

Reputation: 33369

I recommend using the new Grand Central Dispatch API instead.

For example:

-(IBAction)clickToLaunchAppButtonClicked:(id)sender {
  //I want to hide the click to load app button
  [clickToLoadButton setEnabled:NO];
  [clickToLoadButton setHidden:YES];

  // wait one second
  dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);
  dispatch_after(popTime, dispatch_get_main_queue(), ^{

    //I want to show the loading label
    [loadingLabel setEnabled:YES];
    [loadingLabel setHidden:NO];

    //I want to show the loading progress bar and initialize it
    [loadingProgressBar setHidden:NO];
    [loadingProgressBar startAnimation:self];

    // execute the rest after 3 seconds
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^{

      //I want to stop the loading progress bar animation
      [loadingProgressBar stopAnimation:self];

      //I want to hide the loading progress bar and loading label
      [loadingLabel setHidden:YES];
      [loadingLabel setEnabled:NO];
      [loadingLabel setHidden:YES];
    });
  });
}

There are three advantages:

  • It's less code, and cleaner. You don't need to define extra methods and all your code is in one place.
  • The GCD api is increadibly fast, though in your example it probably doesn't matter much, sometimes this is important, especially on an iPhone where "fast" also means "longer battery life"
  • The code to be executed shares the scope with the code that calls it. Any variables in the outer code, are available in the code to be executed later

Upvotes: 1

Jesse Black
Jesse Black

Reputation: 7986

You can place the code you want to run on the 3 second delay in another method (delayedLoad) and use performSelector: withObject: afterDelay:

[self performSelector:@selector(delayedLoad) withObject:nil afterDelay:3.0];

EDIT - spelling it out more in response to your comment

to create the other method, include this code in the same .m file (AppDelegate.m or similar)

-(void)delayedLoad
{

//I want to stop the loading progress bar animation
[loadingProgressBar stopAnimation:self];

//I want to hide the loading progress bar and loading label
[loadingLabel setHidden:YES];
[loadingLabel setEnabled:NO];
[loadingLabel setHidden:YES];
}

And your existing method becomes

-(IBAction)clickToLaunchAppButtonClicked:(id)sender; {
//I want to hide the click to load app button
[clickToLoadButton setEnabled:NO];
[clickToLoadButton setHidden:YES];

//***I want to make the app wait for 1 second (This is where I'm stuck!)***

//I want to show the loading label
[loadingLabel setEnabled:YES];
[loadingLabel setHidden:NO];

//I want to show the loading progress bar and initialize it
[loadingProgressBar setHidden:NO];
[loadingProgressBar startAnimation:self];
[self performSelector:@selector(delayedLoad) withObject:nil afterDelay:3.0];
}

This is how you implement the 3 second delay. Hopefully you can extend this to implement the 1 second delay

Upvotes: 0

Related Questions