Posts Tagged ‘delay’

Timers

April 27th, 2009

Timers – believe me or not, but they are useful not only in programming stopwatches.

Let’s give some examples.

  • To show a welcome screen and to close it after several seconds
  • You are making a game and you would like to display an info how long user is playing current stage, without comparing NSDate (start and current).
  • To create an animation without fade in / fade out effect.

Using timer (NSTimer) you are able to launch any task after given time or repeat it periodically.

I will give you an description with code for each of above examples.

Welcome screen

Welcome screen is shown only once during launch so there is no need to create any information in header file of your class about NSTimer. All you need to do is to add this line to your viewDidLoad method:

	[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(closeWelcomeScreen) userInfo:nil repeats:NO];
And to develop a closeWelcomeScreen method:
-(void)closeWelcomeScreen {
	[welcomeScreen removeFromSuperview];
}
closeWelcomeScreen will be called in 1.5 seconds after view was loaded. Remember to set the repeats property to NO this time. If you set YES, the method closeWelcomeScreen would be called every 1.5 seconds.
Right now we are simply removing the welcomeScreen, of course it’s up to you if you decide to perform an animation to change it’s alpha property it or to add something on top of welcomeScreen.

How long?

Now we will create a timer that will call the method every 0.01 second. In header file we need to add a float variable (float time;) and it’s also a label to show somewhere the value of this variable:

@interface MyView : UIViewController {
	IBOutlet UILabel *myLabel;
	float time;
}

Now in viewDidLoad or any other method you will call by yourself, add:

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

And you need to implement countTime method:

-(void)countTime {
	time += 0.01;
	myLabel.text = [NSString stringWithFormat:@"%.2f",time];
}

As you see, this time NSTimer’s repeats property is set to YES, and that’s why it will call countTime method every 0.01 second.

Animations using NSTimer

As I told you before using typical animations (and transformations) ([UIView beginAnimations:nil context:NULL] and [UIView commitAnimations]) you get the nice fade in and out effect. To perform a rotation for example you have to create a similar timer like in code above, with tiny difference. It won’t be changing label’s text but transforming it using each time bigger angle.

	[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(countTime) userInfo:nil repeats:YES];
-(void)countTime {
	rotation += 0.001;
	myLabel.transform = CGAffineTransformMakeRotation(M_PI*rotation);
} 

Remember to add in your header file rotation variable: float rotation;

Stoping NSTimer

In each of above examples when NSTimer repeats itself you can’t stop it – the time will grow and/or your object will be rotated. To obtain it you have to add the NSTimer object to the header and later in implementation to use it’s invalidate method whenever/wherever you want to stop it. Below I show you an example of the timer that will make a full rotation of myLabel and invaliate itself.

Header:

@interface MyView : UIViewController {
	IBOutlet UILabel *myLabel;
	float rotation;
	NSTimer *rotationTimer;
}

Starting the timer:

	rotationTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(rotate) userInfo:nil repeats:YES];
And the rotate method:
-(void)rotate {
	if (rotation >= 2.0) {
		[rotationTimer invalidate];
		return;
	}
	rotation += 0.001;
	myLabel.transform = CGAffineTransformMakeRotation(M_PI*rotation);
}
You can call invalidate method anywhere in your project. A button can invalidate your timer or the timer itself as shown above.

Personal experience

Timers can be more complex than just counting a time or perform a simple task. If you use timer as a run loop of your game for example, be careful. If many methods can invalidate the timer you should check if it cannot be invalidated twice sometimes. It will crash your application. Although NSTimer has the boolean method isValid, once NSTimer is invalidated you can’t use this property. Declaring any NSTimer I also add the boolean variable with similar name:

NSTimer *myTimer;
bool myTimerInvalidated;

Each time I start the timer I set the boolean equals NO, each time I want to invalidate the timer I use:

if (!myTimerInvalidated) {
	myTimerInvalidated = YES;
	[myTimer invalidate];
}

Download the sample project to see live example of NSTimers.

xcodeproj

Download the project