I have NSTimer to display an image after 2 seconds when i click on button. It is working fine when I Click on a Button, But the problem is When I double Click the Button the NSTimer is Not Stopping. Continuously it is displaying images(calling NSTimer method) without Clicking on the button for Next Time. How to stop the NSTimer when i double Click / more Clicks on that button at a time.
*This is my Code*
-(void)buttonClicked
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(timerClicked) userInfo:nil repeats:YES];
imgviewtransparent.image = [UIImage imageNamed:[imagesArray objectAtIndex:i]];
}
-(void)timerClicked
{
[timer invalidate];
timer = nil;
}
With double Click it will schedule timer twice.
You can create a BOOL property to avoid this if you want.
-(void)viewDidLoad{
[super viewDidLoad];
//Define all your implementation
//Set BOOL property to no at start
self.isButtonClicked = NO; // You need to define this BOOL property as well.
}
-(void)buttonClicked {
// Return if one click is already in process
if (self.isButtonClicked) {
return;
}
self.isButtonClicked = YES:
timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self
selector:#selector(timerClicked) userInfo:nil repeats:YES];
imgviewtransparent.image = [UIImage imageNamed:[imagesArray objectAtIndex:i]];
}
-(void)timerClicked {
[timer invalidate];
timer = nil;
self.isButtonClicked = NO;
}
Related
PageViewController didFinishAnimating not called when swipe multiple time.
I have a function that recognize that user finish animation swipe and I start to move alone the page every 4 second.
sometimes didFinishAnimating not call in the last swipe.
-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
NSLog(#"\n\n\n didFinishAnimating \n\n\n");
_isAnimateWorking = NO;
if(completed){
_currentIndex = _nextIndex;
}
else
{
_currentProduct = prev_currentProduct;
_nextIndex = prev_nextIndex;
}
[self StartMoveAloneTimer];
}
-(void) StartMoveAloneTimer {
if (_myticker == nil) {
_myticker = [NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:#selector(GoToNextPage) userInfo:nil repeats:YES];
}
}
I have a NSTimer that works fine and counts down in 1 second intervals. But I want the timer to trigger immediately without that 1 second delay.
I thought calling [timer fire] should work for this (described here) but it doesn't make a difference. I want the timer to be triggered as fast as if I scheduled the interval to be 0.
- (void)onStartButtonPressed:(UIButton*)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:tv];
NSIndexPath* indexPath = [tv indexPathForRowAtPoint:buttonPosition];
NSInteger index = indexPath.row;
// starts timer for cell at the index path
if (indexPath != nil)
{
NSTimer* timer = [timerArray objectAtIndex: index];
if ([timer isEqual:[NSNull null]]) {
NSLog(#"It's empty");
// start timer
NSTimer timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(onTick:)
userInfo:indexPath
repeats:YES];
// [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSLog(#"before timer fire");
[timer fire];
// update data array of timer objects and countdowns
NSInteger selectedTimeIdx = [[selectedTimeIdxArray objectAtIndex: index] integerValue];
NSInteger selectedTime = [pickerTimeArray[selectedTimeIdx] integerValue];
[timerArray replaceObjectAtIndex:index withObject:timer];
[countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:selectedTime*60]];
} else {
NSLog(#"It's not empty");
}
}
- (void)onTick:(NSTimer *)timer
{
NSLog(#"on tick method starts");
// get the timer's owner's index path and update label
NSIndexPath* indexPath = [timer userInfo];
NSInteger index = indexPath.row;
// update countdown
NSInteger countdown = [[countdownArray objectAtIndex: index] integerValue];
[countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:--countdown]];
// NSLog(#"countdown: %ld", (long)countdown);
[tv reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
// NSLog(#"Tic indexPath: %#", indexPath);
if (countdown == 0)
{
[timer invalidate];
timer = nil;
}
}
The timer works but I don't want there to be a 1 second delay for it to be initially triggered. I want the timer to start immediately.
Edit: I added logs that rmaddy suggested. Here are my results (I changed the interval time to 3):
2015-05-19 14:41:02.827 restaurant[4206:77915] before timer fire
2015-05-19 14:41:02.827 restaurant[4206:77915] on tick method starts
2015-05-19 14:41:05.827 restaurant[4206:77915] on tick method starts
2015-05-19 14:41:08.828 restaurant[4206:77915] on tick method starts
Why not just call your method before the timer
[self onTick:nil];
//usual timer code here
Edit: as stated by rmaddy
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(onTick:)
userInfo:indexPath repeats:YES];
[self onTick:timer];
Some of the comments were really helpful, especially adding the logs as suggested by rmaddy. It turns out [timer fire] was working fine.
I had confused myself because my timerLabel which displayed the countdown was being updated in my cell with a 1 second delay, and I thought that meant the timer instantiation was delayed.
Once I saw what the problem really was, all I had to do was update the cell in the same block that I instantiated the timer (instead of just onTick).
I just added this to my onStartButtonPressed and everything works as I want it to.
// update countdown
NSInteger countdown = [[countdownArray objectAtIndex: index] integerValue];
[countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:--countdown]];
// cell label gets updated right at start button press
[tv reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
Leaving here in case it helps anyone.
I have the code below displaying an ActivityIndicator before calling a GCD process. The background process throws a Notification when it's complete or encounters an error. I am calling the stopAnimating method in the error handler but the spinner keeps spinning. Why?
UIActivityIndicatorView *mIndicator;
#interface VC_Main ()
#end
- (void)viewDidLoad
{
[super viewDidLoad];
[NSLog(#"viewDidLoad");
// create indicator for download activity
mIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[mIndicator setCenter:CGPointMake([self getScreen].x /2.0, [self getScreen].y / 2.0)]; // landscape mode
[self.view addSubview:mIndicator];
// fire off a single interval
[NSTimer scheduledTimerWithTimeInterval:0.0
target:self
selector:#selector(timerTask:)
userInfo:nil
repeats:NO];
...
}
- (void) timerTask:(NSTimer *) timer
{
NSLog(#"DEBUG: timertask timeout");
[mIndicator startAnimating];
...
}
// if there is an error parsing xml downloaded from server, it notifies here
- (void) xmlError:(NSNotification *)note
{
NSLog(#"error parsing xml");
[mIndicator stopAnimating]; // this doesn't work
// fire off a refresh using retry timeout
[NSTimer scheduledTimerWithTimeInterval:TIMEOUT_RETRY_MINS
target:self
selector:#selector(timerTask:)
userInfo:nil
repeats:NO];
NSLog(#"will retry in %d", TIMEOUT_RETRY_MINS);
}
As with every UIKit call, you need to do it on the main thread.
Just do:
dispatch_async(dispatch_get_main_queue(), ^{
[mIndicator stopAnimating];
});
and it should work
Perhaps you retry too soon?
scheduledTimerWithTimeInterval:TIMEOUT_RETRY_MINS
It's supposed to be seconds, not minutes.
I want a label to be shown for 0.4 seconds and then hidden for 0.8 seconds - in an infinite loop.
How can I pull that off?
NSTimer and UIViews hidden property would be one possibility
I would say to use NSTimer. You could do it the following way:
Say your label is myLabel:
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
You should create a method to be called by NSTimer:
- (void)changeLabelState:(NSTimer *)timer
{
if(self.myLabel.hidden == TRUE)
{
self.myLabel.hidden = FALSE; //change comparassion to assing
[NSTimer scheduledTimerWithTimeInterval:0.4
target:self
selector:#selector(changeLabelState:)
userInfo:nil
repeats:NO];
}
else
{
self.myLabel.hidden = TRUE;
[NSTimer scheduledTimerWithTimeInterval:0.8
target:self
selector:#selector(changeLabelState:)
userInfo:nil
repeats:NO];
}
}
And initialize NSTimer somewhere like so:
[NSTimer scheduledTimerWithTimeInterval:0.4
target:self
selector:#selector(changeLabelState:)
userInfo:nil
repeats:NO];
Note that you could also do the following:
[self performSelector:#selector(changeLabelState:) withObject:nil afterDelay:0.4];
- (void)changeLabelState:(NSTimer *)timer
{
if(self.myLabel.hidden == TRUE)
{
self.myLabel.hidden = FALSE;
[self performSelector:#selector(changeLabelState:) withObject:nil afterDelay:0.4];
}
else
{
self.myLabel.hidden = TRUE;
[self performSelector:#selector(changeLabelState:) withObject:nil afterDelay:0.8];
}
}
Something Like the below.
In viewDidLoad:
NSTimer *silly = [NSTimer timerWithTimeInterval:0.4 target:self selector:#selector(question) userInfo:nil repeats:YES];
Function
-(void)question {
if(label.isHidden){
label.hidden = false;
} else {
label.hidden = true;
}
}
Make sure you have a UILabel defined in scope of this function and it should work. UNTESTED.
I have a countdown timer where the user can input the time they want to start from using a countdown timer like in the clock app. The problem is, I can't figure out how to make the timer actually count down. I have already made the UI and have most of the code, but I don't know what would go in the updateTimer method I have. Here is my code:
- (void)updateTimer
{
//I don't know what goes here to make the timer decrease...
}
- (IBAction)btnStartPressed:(id)sender {
pkrTime.hidden = YES; //this is the timer picker
btnStart.hidden = YES;
btnStop.hidden = NO;
// Create the timer that fires every 60 sec
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
}
- (IBAction)btnStopPressed:(id)sender {
pkrTime.hidden = NO;
btnStart.hidden = NO;
btnStop.hidden = YES;
}
Please let me know what goes in the updateTimer method to let the timer decrease.
Thanks in advance.
You would track the overall time left with a variable. The updateTimer method will be called every second, and you would reduce the time left variable by 1 (one second) each time updateTimer method is called. I have given an example below, but I have renamed updateTimer to reduceTimeLeft.
SomeClass.h
#import <UIKit/UIKit.h>
#interface SomeClass : NSObject {
int timeLeft;
}
#property (nonatomic, strong) NSTimer *timer;
#end
SomeClass.m
#import "SomeClass.h"
#implementation SomeClass
- (IBAction)btnStartPressed:(id)sender {
//Start countdown with 2 minutes on the clock.
timeLeft = 120;
pkrTime.hidden = YES;
btnStart.hidden = YES;
btnStop.hidden = NO;
//Fire this timer every second.
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(reduceTimeLeft:)
userInfo:nil
repeats:YES];
}
- (void)reduceTimeLeft:(NSTimer *)timer {
//Countown timeleft by a second each time this function is called
timeLeft--;
//When timer ends stop timer, and hide stop buttons
if (timeLeft == 0) {
pkrTime.hidden = NO;
btnStart.hidden = NO;
btnStop.hidden = YES;
[self.timer invalidate];
}
NSLog(#"Time Left In Seconds: %i",timeLeft);
}
- (IBAction)btnStopPressed:(id)sender {
//Manually stop timer
pkrTime.hidden = NO;
btnStart.hidden = NO;
btnStop.hidden = YES;
[self.timer invalidate];
}
#end