Change NSTimer interval after a certain number of fires - objective-c

In the following code, the NSTimer interval is set at 1 second between each picture. My goal is to change the interval after the first two pictures, hello.png and bye.png, to 4 seconds.
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *imageNames = #[#"hello.png",#"bye.png",#"helloagain.png",#"bye again"];
self.images = [[NSMutableArray alloc] init];
for (int i = 0; i < imageNames.count; i++) {
[self.images addObject:[UIImage imageNamed:[imageNames objectAtIndex:i]]];
}
self.animationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 95, 86, 90)];
self.animationImageView.image = self.images[0];
[self.view addSubview:self.animationImageView];
self.animationImageView.userInteractionEnabled = TRUE;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(changeImage:) userInfo:nil repeats:YES];
}
-(void)changeImage:(NSTimer *) timer {
if (counter == self.images.count - 1 ) {
counter = 0;
}else {
counter ++;
}
self.animationImageView.image = self.images[counter];
}

my goal is to change the interval
You cannot change a timer in any way. To change the firing interval, invalidate and destroy the timer and make a new timer with the new interval.
To do that, you will need to have kept a reference to the timer, as a property of your view controller (something that you have fatally failed to do in your implementation - you would have had no way to stop the timer, and you would have crashed if your view controller ever went out of existence, or else your view controller would have leaked because the timer retains it).

Make the timer object a member variable. Initially set animation time as 1 second. In the callback invalidate the timer and create a new one with 1 or 4 seconds depending on the counter.
#interface ViewController ()
#property (strong,nonatomic) NSMutableArray *images;
#property (strong,nonatomic) UIImageView *animationImageView;
{
NSTimer *_timer;
}
#end
#implementation ViewController {
NSInteger counter;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *imageNames = #[#"hello.png",#"bye.png",#"helloagain.png",#"bye again"];
self.images = [[NSMutableArray alloc] init];
for (int i = 0; i < imageNames.count; i++) {
[self.images addObject:[UIImage imageNamed:[imageNames objectAtIndex:i]]];
}
self.animationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 95, 86, 90)];
self.animationImageView.image = self.images[0];
[self.view addSubview:self.animationImageView];
self.animationImageView.userInteractionEnabled = TRUE;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(bannerTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.animationImageView addGestureRecognizer:singleTap];
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(changeImage:) userInfo:nil repeats:YES];
}
-(void)changeImage:(NSTimer *) timer {
[_timer invalidate];
if (counter == self.images.count - 1 ) {
counter = 0;
}else {
counter ++;
}
if(counter == 0 || counter == 1)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(changeImage:) userInfo:nil repeats:YES];
}
else if(counter == 2 || counter == 3)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:#selector(changeImage:) userInfo:nil repeats:YES];
}
self.animationImageView.image = self.images[counter];
}

The best/simpliest way :
-(void)Timer{
// Do what you want here
// modify the frequency value if you want.
[NSTimer scheduledTimerWithTimeInterval:frequence target:self selector:#selector(Timer) userInfo:nil repeats:NO];
}
Frequence is a variable that contains the interval.
You just need to call Timer method by yourself the first time ;)
For you, it would give
-(void)changeImage{
if (counter == self.images.count - 1 )
counter = 0;
else
counter ++;
frequence = (counter < 2)?1:4;
self.animationImageView.image = self.images[counter];
[NSTimer scheduledTimerWithTimeInterval:frequence target:self selector:#selector(changeImage) userInfo:nil repeats:NO];
}

Related

Stop Method Execution after 5 Minute

How can i stop the execution of the method after a certain time?
I am calling method as below:
[NSTimer scheduledTimerWithTimeInterval:5.0f
target:self
selector:#selector(doSomeTask) userInfo:nil repeats:YES];
Here i have given interval of 5 Seconds. So this method will get called after every 5 seconds, So once the reaches to specified time i want to stop this method execution.
Take a counter variable, and increase in every call by 5 (as time interval is 5 sec ) like
counter = counter+5;
-(void) doSomeTask {
if (counter<=60) { // 5 min = 300 300/5 = 60
// Write method body here
counter = counter+5
}
else {
[timer invalidate];
}
}
If you want to stop execution of the method after 5 min. Then you can add code like this
#interface YourClass () {
int count;
}
#end
-(void)viewDidLoad {
count = 5;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(doSomeTask) userInfo:nil repeats:YES];
}
-(void) doSomeTask
{
count = count + 5;
if (count==300)
{
[timer invalidate];
timer=nil;
}
}
#define TIMER_LIFE_IN_SECONDS 300.0
#interface YourClass () {
NSTimeInterval _startTime;
}
self.timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(doSomeTask) userInfo:nil repeats:YES];
_startTime = [NSDate timeIntervalSinceReferenceDate];
- (void) doSomeTask
{
// do thing
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
if (now - _startTime > TIMER_LIFE_IN_SECONDS) {
[self.timer invalidate];
self.timer = nil;
}
}
you can try like this
NSTimer *reachTimer;
NSInteger secondsLeft;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
secondsLeft = 0;
reachTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
-(void)updateCounter:(NSTimer *)theTimer{
secondsLeft = secondsLeft+5;
if(secondsLeft>=300) // 60sec * 5min= 300
{
[reachTimer invalidate];
}
}
Try this;
int count;
NSTimer *timer;
-(void)startTimertillLimit:(int)limit {
count = 0;
timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(doSomething:)
userInfo:[NSString stringWithFormat:#"%d",limit]
repeats:YES];
}
-(void)doSomething:(NSTimer*)sender
{
int limit = (int)[sender.userInfo intValue];
count = count + 5;
if (count > limit)
{
[timer invalidate];
timer=nil;
count = 0;
}
}
Try to create NSTimer that will be called after some time only once :
NSTimer *previous [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(doSomeTask) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:300 target:self selector:#selector(stopPrevious) userInfo:nil repeats:NO];
-(void)stopPrevious{
[previous invalidate];
}

Change array of images with NSTimer

I want to implement a auto change image gallery. here is my code in the controller. i have a uiimageview named image. i want to link the array of image to my image view to let it auto change after a few seconds. What should i do??
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelector:#selector(changeImage) withObject:nil afterDelay:2];
}
-(void)changeImage {
NSArray *images = [NSArray arrayWithObjects:[UIImage imageNamed:#"animated-fish-1.jpg"], [UIImage imageNamed:#"tumblr_7"], [UIImage imageNamed:#"th_nature_4.jpg"],nil];
image.animationImages = images;
// how to let the array of image load and link to the perform selector??
// what should i continue from here?
}
Store the images in an ivar
#interface YourClass : SomeSuperClass
#property (nonatomic, strong) NSArray *images;
#end
Don't start the timer in viewDidLoad as the view will not be on the screen yet so there is no point - move it to viewDidAppear:
- (void)viewDidLoad
{
[super viewDidLoad];
self.images = #[ ... ]; // or pass these into the class
self.imageView.image = self.images[0];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:2
target:self
selector:#selector(changeImage:)
userInfo:nil
repeats:YES];
}
-(void)changeImage:(NSTimer *)timer
{
NSInteger currentIndex = [self.images indexOfObject:self.imageView.image];
NSInteger nextIndex = (currentIndex + 1) % self.images.count;
self.imageView.image = self.images[nextIndex];
// If for any reason you need to cancel the image rotation
if ([self shouldCancelImageRotation]) {
[timer invalidate];
}
}
To animate the images using timer, try this
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(animateImages)
userInfo:nil
repeats:YES];
imageCount = 1;
}
-(void)animateImages
{
imageCount = imageCount + 1;
NSString *imageName = [NSString stringWithFormat:#"image%i.png"];
[theImage setImage:[UIImage imageNamed:imageName]];
}
You should use NSTimer, per example, you can use this method :
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
This method allow you to define a selector to use and repeats every x seconds
try like this ,
take one global varaible index
- (void)viewDidLoad{
[super viewDidLoad];
index=0;
NSArray *images = [NSArray arrayWithObjects:[UIImage imageNamed:#"animated-fish-1.jpg"], [UIImage imageNamed:#"tumblr_7"], [UIImage imageNamed:#"th_nature_4.jpg"],nil];
imageview.image = [images objectAtIndex:index];
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
}
-(void)changeImage {
index++;
if(index==[images count]){
index=0;
}
imageview.image = [images objectAtIndex:index];
}

Displaying NSTimer value on label

There is a button and a label in my project.After clicking the button i need to start a NSTimer which displays it's value on label.For example 1sec.I am not sure whether timer returns value.is there any other way to do this?.
in the function of button click
{
NSTimer *t;
t=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showTimer) userInfo:nil repeats:YES];
}
in showTimer function
-(void)showTimer{
static int i=0;
static int min=0;
if(i>=59){
i=0;
min++;
} else {
i++;
}
yourLabel.text=[NSString stringWithFormat:#" %d:%d ",min,i];
}
NSTimer *aTimer = [NSTimer timerWithTimeInterval:(1) target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:aTimer forMode: NSDefaultRunLoopMode];
int i=0;
- (void)timerFired:(NSTimer*)theTimer
{
if(condition)
{
// timer repeat
// your actions
i++;
int conseconds = i % 60;
int conminutes = (i / 60) % 60;
timelable.text=[NSString stringWithFormat:#"%02d:%02d", conminutes,conseconds];
[theTimer isValid];
}
else
{
// your actions
//timer stopped
[theTimer invalidate];
}
}

Using NSTimer, calling two functions with the same name, different parameters, both use scheduledTimerWithTimeInterval

I'm trying to write my own fade-ins and fade-outs using the AVAudioPlayer as a helper.
My problem is this: I have two method definitions with the same name, but one takes an int and the other takes no parameters. Is there a way for me to tell NSTimer which one to call? Couldn't really make sense of the documentation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html
-(void) stopWithFadeOut
{
if (_player.volume > 0.1) {
[self adjustVolume:-.1];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(stopWithFadeOut) userInfo:NULL repeats:NO];
}
else {
[self stop];
}
}
and
-(void) stopWithFadeOut:(NSString *)speed
{
int incr = [speed intValue];
if (_player.volume > 0.1) {
[self adjustVolume:-incr];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(stopWithFadeOut) userInfo:NULL repeats:NO];
}
else {
[self stop];
}
}
Those actually have different names. The colon is significant, so the name (and hence the argument to #selector()) of the second method is stopWithFadeOut:.*
To create the timer, then, you want:
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(stopWithFadeOut:)
userInfo:NULL //^ Note! Colon!
repeats:NO];
However, this method is incorrect, because an NSTimer passes itself to its action method; it's not possible for you to pass in an arbitrary object. This is what the userInfo: parameter is for. You can sort of attach some object to the timer, and retrieve it inside the action method using the userInfo method, like so:
- (void)stopWithFadeOut: (NSTimer *)tim
{
NSString * speed = [tim userInfo];
int incr = [speed intValue];
if (_player.volume > 0.1) {
[self adjustVolume:-incr];
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(stopWithFadeOut:)
userInfo:speed
repeats:NO];
}
(Also note that this means your first method isn't really a correct NSTimer action method, because it doesn't have the NSTimer parameter.)
*The compiler wouldn't have let you declare or define two methods with the same name in one class, and the parameter type doesn't count as part of the selector, so trying to create -(void)dumblethwaite:(int)circumstance; and -(void)dumblethwaite:(NSString *)jinxopotamus; in one class doesn't work.
So this is what I came up with. Thanks Josh.
-(void) pauseWithFadeOut
{
NSNumber *incr = [[NSNumber alloc] initWithFloat:0.1];
while (_player.volume > 0.1) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(fadeOut) userInfo:incr repeats:NO];
}
}
-(void)fadeOut: (NSTimer*) deleg
{
int incr = (int) [deleg userInfo];
if (_player.volume > 0.1) {
[self adjustVolume:-incr];
}
}
-(void) pauseWithFadeOut:(NSString *)speed
{
NSNumber *incr = [[NSNumber alloc] initWithFloat:[speed floatValue]];
while (_player.volume > 0.1) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(fadeOut) userInfo:incr repeats:NO];
}
[self pause];
}
-(void) stopWithFadeOut
{
NSNumber *incr = [[NSNumber alloc] initWithFloat:0.1];
while (_player.volume > 0.1) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(fadeOut) userInfo:incr repeats:NO];
}
}
-(void) stopWithFadeOut:(NSString *)speed
{
NSNumber *incr = [[NSNumber alloc] initWithFloat:[speed floatValue]];
while (_player.volume > 0.1) {
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(fadeOut) userInfo:incr repeats:NO];
}
[self stop];
}

Why does this NSTimer crash?

http://www.youtube.com/watch?v=5al6qqRzzQg when i click on the start more than once???
what will i need to do
#import "FirstViewController.h"
#implementation FirstViewController
-(IBAction)start;{
myticker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
}
-(IBAction)stop;{
[myticker invalidate];
}
-(IBAction)reset;{
time.text = #"0";
}
-(void)showActivity;{
int currentTime = [time.text intValue];
int newTime = currentTime + 1;
time.text = [NSString stringWithFormat:#"%d", newTime];
}
- (void)didReceiveMemoryWarning
Change your start and stop methods to this:
-(IBAction)start;{
[myticker invalidate];
myticker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
}
-(IBAction)stop;{
[myticker invalidate];
myticker = nil;
}
That will stop it crashing. Also, you should add this:
-(void)dealloc
{
[myticker invalidate];
}
add a bool variable to the header of your class, like timerIsActive
-(IBAction)start;{
if (!timerIsActive) {
myticker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
timerIsActive = YES;
}
}
-(IBAction)stop;{
timerIsActive = NO;
[myticker invalidate];
}