I have a table view that is broken up into alphabetic sections. I am displaying an animated banner in a UIImage View in the footer of each section, and need to determine which image is displayed when the UIImage View is clicked. I set a timer right before I make the call to startAnimating. The timer is to fire every 5 seconds, at the same rate that the animation changes, but the timer is firing much faster. Sometimes it will fire 2 or 3 times within that 5 second period. Here is the code where I start the timer and the animation:
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger) section {
...
imgAdBar = [[bannerView alloc]initWithFrame:CGRectMake(footer.frame.origin.x,footer.frame.origin.y,footer.frame.size.width,footer.frame.size.height)];
imgAdBar.image=[UIImage imageNamed:[NSString stringWithFormat:#"%#", [animationArray objectAtIndex:0]]];
[imgAdBar saveBannerArray:animationArray];
[imgAdBar setUserInteractionEnabled:YES];
imgAdBar.animationImages = images;
imgAdBar.animationDuration=[images count]*5;
imgAdBar.animationRepeatCount=0;
timerCount=0;
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(timerRunning:) userInfo:nil repeats:YES];
[imgAdBar startAnimating];
[footer addSubview:imgAdBar];
footer.backgroundColor = [UIColor clearColor];
}
return footer;
}
And here is the selector:
-(void)timerRunning:(NSTimer*)theTimer
{
NSLog(#"timerCount=%d",timerCount);
imgAdBar.timerCount=timerCount;
if (timerCount==numAnimationImages) {
timerCount=0;
}
NSLog(#"currentImage=%#",[animationArray objectAtIndex:timerCount]);
timerCount++;
}
I plan to use that timer to index into my image array so that I can tell which is displayed. Anyone have any idea why it's not firing when it should? Thanks for any assistance!
You have to use NSTimer as an property ...
Since viewForFooterInSection is called several times for many sections you have to invalidate before you reinitialize it or you have to check for null following is the code..
Invalidate:
NSTimer *timer; // declare in ViewDidLoad
// code in viewForFooterInSection
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: #selector(handleTimer:)
userInfo: nil
repeats: YES];
Check for nil
if (timer == nil) {
timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: #selector(handleTimer:)
userInfo: nil
repeats: YES];
}
Hope it should help..
Declare an NSTimer as property in your header file
#propterty (nonatomic, retain) NSTimer *someTimer;
In the line where you fire the timer
someTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(timerRunning:) userInfo:nil repeats:YES];
Don't forget to release it in -(void)viewDidUnload
[someTimer release];
Since you do not use the value of timerCount unless there is a click, you do not need to update it on timer: it is sufficient to store the time at the moment when you start animation. Knowing that each image is shown for five seconds, you can calculate the index of the image being displayed by taking the difference, in seconds, between the time of the click and the time when you started the animation, dividing it by five, and taking the remainder of the division by the total number of images.
Say you have ten images, each displaying for five seconds in a loop. Let's also say that the animation has started at 08:15:51. Now let's say there's a click at 08:19:23, or 212 seconds after the animation has started. After dividing by five you get 42; taking the remainder of the division by ten, you get 2. Therefore, you know that the user has clicked on the third image in the animation loop (as usual, indexes start from zero).
Related
I'm making a game where you are supposed to move an image between other image without colliding. Everything worked fine until I added coins to the game. When the image hits a coin, it's supposed to make a sound (which it does) and add +1 to the coin label. The problem is, when I add the code to make the coinlabel get +1, the image that I'm moving will stop and go back to starting position. The same thing happened to me when I was using an NSTimer (because users playing the app had time on finish the level.) But everytime the label counted a number, the game stopped again and the ball was put back to the starting position.
Here is some code for the game.
-(IBAction)left {
goLeft = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(goLeft) userInfo:nil repeats:YES];
if (goLeft == nil) {
goLeft = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(goLeft) userInfo:nil repeats:YES];
}
}
-(IBAction)stopLeft {
[goLeft invalidate]; goLeft = nil;
}
-(void)goLeft {
image.center = CGPointMake(image.center.x -3.5, image.center.y);
{
//Coins
if (CGRectIntersectsRect(image.frame, coin1.frame)) {
coin1.hidden = YES;
[self getcoins];
}
-(void)getcoins{
//Here i have a avaudioplayer playing a noise (dont need to show that as that works fine)
//Then the +1 to label
coinlabel.text = [[NSNumber numberWithInt:([coinlabel.text intValue] + 1)] stringValue];
// And when i add this and the image hits the coin, the image goes back to the starting position. But i want it not to stop or anything, but continue.
}
The left action is connected to touch down. And stopleft is connected to touch up inside. Hope you understand and thanks for any help.
I am showing a count down timer using UILabel and NSTimer -
-(void)a_Method
{
[coolTimeLbl setNeedsDisplay];
coolTime = 5; // it is an int
coolingTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(cooling) userInfo:nil repeats:YES]; // NSTimer
}
-(void)cooling
{
if (coolTime>0)
{
coolTime = coolTime-1;
NSLog(#" coolTime----%#",coolTime);
coolTimeLbl.text =[NSString stringWithFormat:#"%d",coolTime];
NSLog(#" coolTimeLbl----%#",coolTimeLbl.text);
}
else
{
[coolingTimer invalidate];
coolingTimer = nil;
}
}
The first time everything works fine and I am getting coolTimeLbl.text as - 4 3 2 1 0
But the second time when I call aMethod, coolTimeLbl is not getting updated properly - it is like 3 2 0 etc (some weird behavior)
However both NSLogs (coolTime & coolTimeLbl) print perfectly all the times and values.
Why does this happen? I tried many ways like NSNotification etc.
Please help me to fix this.
If you're calling a_Method more than once before coolingTimer invalidates itself, the timer will tick more than once.
You should add some boolean like ;
BOOL isTimerValid;
in a_Method,
if(!isTimerValid)
{
isTimerValid = YES;
coolingTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(cooling) userInfo:nil repeats:YES]; // NSTimer
}
in cooling,
else
{
isTimerValid = NO;
....
}
Had the same issue in one of my viewControllers and another one was working OK with same NSTimer code. Looked at about 20 SO threads to get it solved. No luck. In my case
myLabel.opaque = false
solved it.
Don't ask me why.
I and many others have a issue mathematically causing a function to be called more and more often. My goal is to call the code inside the if statement more and more often. The function is called every .01 seconds. I would like the first time it runs is at 1 second, then faster and faster until it holds off at about .3. I need to know what to put in the SOMETHING.
The Function is called every .01 seconds by a NSTimer.
The code is:
-(IBAction)redmaker:(id)sender{
refreshrate = refreshrate+1;
if(SOMETHING){
int rand =arc4random() %65;
UIButton *button = (UIButton *)[self.view viewWithTag:rand];
button.backgroundColor = [UIColor colorWithRed:255 green:0 blue:0 alpha:1];
button.enabled = YES;
deathtimes[rand] = 10;
rate = rate+1;
refreshrate = 0;
}
You should use an NSTimer to call your method. Define an NSTimer in your header file.
Class.h
NSTimer *timer;
double interval;
Class.m
//put the following two lines in viewDidLoad, or some other method
interval = 1.0
timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:#selector(redmarker:) userInfo:nil repeats:NO];
-----
//put this at the bottom of your if statement
if (interval > 0.3)
{
[timer invalidate];
//change this value to something greater to call the method faster
interval -= 0.05;
timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:#selector(redmarker:) userInfo:nil repeats:NO];
}
You may experience an issue that causes your game to slow down. If that occurs, then it is possible that the main thread is unable to handle the timer, the buttons, and other actions all at the same time. You will want to look into using Grand Central Dispatch.
Repeating timers always use the same time interval. You can't change it.
If you want a timer on a decreasing interval, create a non-repating timer that triggers a new timer with the same selector each time it fires. Use an instance variable to hold the interval, and subtract some amount from the interval value each time it fires.
As for your "if (SOMETHING)", nobody else can tell you the conditions in your code that would decide what to do.
Can't you use Grand Central Dispatch with a recursive method like this:
#import "ViewController.h"
#interface ViewController ()
{
CGFloat fireTime;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
fireTime = 1.0;
// initial call to method
[self foo];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)foo
{
NSLog(#"Hello at, timer fired off after %lf", fireTime);
if (fireTime > 0.3)
{
// decrement timer
fireTime -= 0.1;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(fireTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self foo];
});
}
#end
In theory this progress bar should last 7 seconds, however it seems to run a little long. My math has to be incorrect or I'm overlooking something.
Timer should be firing 100 times in 1 second and the progress bar should take about 7 times longer than that to reach 1.0
Any help would be greatly appreciated.
- (void)startTimer;
{
[pBar showProgress:self.progress];
[self.timer invalidate];
self.timer = nil;
if (self.progress < 1.0) {
CGFloat step = 0.01;
self.timer = [NSTimer scheduledTimerWithTimeInterval:step target:self
selector:#selector(startTimer)
userInfo:nil repeats:NO];
self.progress = self.progress + 0.00143;
} else {
[self performSelector:#selector(stopProgress)
withObject:nil afterDelay:0.5];
}
}
You should not update as often as you do. 100 times per second is way too often. 60 would be sufficient to achieve a good frame-rate in theory. However a UIProgressBar can update its value with an animation. Hence you only need to update say 70 times in total or 10 times per second and make the changes with an animation.
I would go for 10 animated updates or less. Or you could try to update with one animation:
[UIView animateWithDuration:7.0 animations:^{
[progressView setProgress:1.0 animated:YES]; //maybe try animated: NO here
} completion:^(BOOL finished) {
//ended
}];
While I did not test this approach, it seems far cleaner than manually performing what essentially is a timed animation of the progress.
I just want to run a certain method for 20 seconds when user presses start button and stop it by it's own rather than using a button to do it. But it should also trigger when ever the user press start button after 20 seconds in next turn.
How can i use NStimer to implement this?
Sorry for not posting any codes
Thanks in advance!
// Assume ARC - otherwise do the proper retains/releases
{
NSTimer *timer; // keep a reference around so you can cancel the timer if you need to
NSDate *timerDate;
}
- (IBAction)buttonPressed:(id)sender
{
// disable button til the time has passed
[sender setEnabled:NO];
// make sure its diabled til we're done here
timerDate = [NSDate date];
NSTimeInterval interval = 1; // 1 gets you a callback every second. If you just wnat to wait 20 seconds change it
// schedule it
timer = [NSTimer ]scheduledTimerWithTimeInterval:time target:self selector:#selector(myTimeRoutine:) userInfo:nil repeats:YES];
}
- (void)myTimeRoutine:(NSTimer *)timer
{
// do something ...
NSTimeInterval interval = -[timerDate timeIntervalSinceNow]; // return value will be negative, so change sign
if(interval >= 20) {
// I'm done now
myButton.enabled = YES; // so it can be tapped again
[timer cancel]; // dont want to get any more messages
timer = nil; // ARC way to release it
timerDate = nil;
}
}