Where do I properly start and invalidate an NSTimer? - ios

in xcode, when i log my NSTimer, It starts atviewDidAppear and stops on viewdiddisappear which is fine, but when I go to an exit segue, the timer resumes (which I don't want to happen because its getting doubled).how do I properly stop it so it won't get doubled when called again?
..when I put in on viewdidload.sure it doesn't get doubled, but it won't start again since I invalidate it viewDidDisappear here is my code
-(void)viewDidAppear:(BOOL)animated{
if (self.timeInc.isValid == NO){
self.timeInc = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateDetailCounter:) userInfo:([Dateformatter2() dateFromString:_DetailModal[1]]) repeats:YES];
}
}
-(void)viewDidDisappear:(BOOL)animated{
[self.timeInc invalidate];
}

You can try this, in the past I had the same problem in viewDidAppear, viewDidDisappear
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
if (self.timerInc) {
[self.timerInc invalidate];
self.timerInc = nil;
}
_timerInc = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(doSth) userInfo:nil repeats:YES];
}
- (void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.timerInc invalidate];
self.timerInc = nil;
}

Related

Moving object back and forth on screen?

I'm just starting out with my first Xcode project and I'm trying to create a square that moves back and forth on the screen using two timers, because I eventually want to make it so that the user can stop the object (which is a square) by tapping a button on the screen.
For now though, I've made the square move to the right side of the screen and move back, but unfortunately I cannot get it to stop at the other side of the screen.
My code right now is this:
- (void)viewDidLoad
{
Square.center = CGPointMake(-9, 246);
SquareTimer1 = [NSTimer scheduledTimerWithTimeInterval:0.004 target:self selector:#selector(moveSquare1)userInfo:nil repeats:YES];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)moveSquare1
{
Square.center = CGPointMake(Square.center.x + 0.3, Square.center.y);
if (Square.center.x > 290){
[SquareTimer1 invalidate];
SquareTimer1 = [NSTimer scheduledTimerWithTimeInterval:0.004 target:self selector:#selector(moveSquare2) userInfo:nil repeats:YES];
}
if (Square.center.x < -9){
[SquareTimer1 invalidate];
}
}
-(void) moveSquare2
{
Square.center = CGPointMake(Square.center.x - 0.3, Square.center.y);
}
The only part of my code that is not working is my second if statement. How can I fix this?
This should do it. Remove that second if from moveSquare1 and place it in moveSquare2
- (void)viewDidLoad
{
Square.center = CGPointMake(-9, 246);
SquareTimer1 = [NSTimer scheduledTimerWithTimeInterval:0.004 target:self selector:#selector(moveSquare1)userInfo:nil repeats:YES];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)moveSquare1
{
Square.center = CGPointMake(Square.center.x + 0.3, Square.center.y);
if (Square.center.x > 290){
[SquareTimer1 invalidate];
SquareTimer1 = [NSTimer scheduledTimerWithTimeInterval:0.004 target:self selector:#selector(moveSquare2) userInfo:nil repeats:YES];
}
}
-(void) moveSquare2
{
Square.center = CGPointMake(Square.center.x - 0.3, Square.center.y);
if (Square.center.x < -9){
[SquareTimer1 invalidate];
// If you want to move the Square back in the right side. Otherwise, comment this below line.
SquareTimer1 = [NSTimer scheduledTimerWithTimeInterval:0.004 target:self selector:#selector(moveSquare1) userInfo:nil repeats:YES];
}
}
Let me know if you have any doubts.

Multiple NsTimer view transition

i am trying to using a Nstimer view transition on multiple view controllers but if i copy and paste it i get an error saying Duplicate declaration of method . how would i fix it ? please explain in your answer how to do this . i found out how to do this from this link .
http://x-code-tutorials.com/2013/06/19/nstimer-trigger-uiviewcontroller-transition/
- (void)viewDidAppear:(BOOL)animated {
[self startTimerMethod];
}
- (void) startTimerMethod {
transitionTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(transitionView) userInfo:nil repeats:NO];
}
- (void) transitionView {
[self performSegueWithIdentifier:#"viewTransition" sender:self];
}
- (void)viewDidAppear:(BOOL)animated {
[self startTimerMethod];
}
- (void) startTimerMethod {
transitionTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(transitionView) userInfo:nil repeats:NO];
}
- (void) transitionView {
[self performSegueWithIdentifier:#"viewTransition" sender:self];
}
You have copy and paste below three methods two times let it define or declare single time:-
-(void)viewDidAppear:(BOOL)animated
-(void) startTimerMethod
-(void) transitionView

NSTimer automatically increases when I change view controller

In my viewController I inserted a timer for a calculation of numbers taken directly from my database of Parse.com.
The timer is working correctly, were inserted in viewDidAppear and in ViewDidDisappear in such a way as to lock the sequence when changing view controller.
The problem I have is that when I change the view controller with the Push the timer does not stop you give an example:
I open the application and the calculation is done correctly with the animation of NSTimer.
Change View, and then I go back with the back button to view where the timer at this point I see that the numbers contiunano to increase every time I change view and go back ...
Can you explain where I'm wrong?
-(void)viewDidAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
[self.navigationController.navigationBar setBackgroundColor:[UIColor clearColor]];
self.title = NSLocalizedString(#"", nil);
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self QueryForViewPrincipal];
[self QueryForCollectionView];
[self ShowBadgeNumber];
[self Timer];
[collectionView reloadData];
}
-(void)Timer{
timer = [NSTimer scheduledTimerWithTimeInterval:0.012 target:self selector:#selector(CalcoloMediadiLaurea) userInfo:nil repeats:YES];
}
-(void) CalcoloMediadiLaurea{
PFUser *CurrentUser = [PFUser currentUser];
NSNumber *NumeroUndici = [NSNumber numberWithInt:11];
NSNumber *NumeroTre = [NSNumber numberWithInt:3];
NSNumber *ValoreMediaPonderata = [CurrentUser objectForKey:FF_USER_MEDIA_PONDERATA];
int FFValoreTre = [NumeroTre intValue];
int FFValoreUndici = [NumeroUndici intValue];
double MediaPonderata = [ValoreMediaPonderata doubleValue];
double RisultatoMoltiplicazioneValoriPonderataUndici;
RisultatoMoltiplicazioneValoriPonderataUndici = MediaPonderata * FFValoreUndici;
double RisultatoMediaLaurea;
RisultatoMediaLaurea = RisultatoMoltiplicazioneValoriPonderataUndici / FFValoreTre;
CalcoloMediaLaureaLabel.text = [NSString stringWithFormat:#"%.1f", FFTickValoreMediaLaurea ];
FFTickValoreMediaLaurea++;
if(FFTickValoreMediaLaurea > RisultatoMediaLaurea){
[timer invalidate];
timer = nil;
}
}
-(void)viewDidDisappear:(BOOL)animated {
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self CalcoloMediadiLaurea];
}
The timer get rescheduled again on view did appear without getting invalidated to the previous one.You should make instance of timer in .h and then hold the reference of timer in it .And on view did appear when you are scheduling the timer just invalidate it and then schedule it again.
if([self.timer isValid])
{
[self.timer invalidate];
self.timer=nil;
self.timer=[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(CalcoloMediadiLaurea:) userInfo:nil repeats:YES];
}
This worked for me which is along the lines of the above answer but a little more explicitly stated.
- (void)viewWillAppear:(BOOL)animated
{
NSTimeInterval secondsBetween = [endDate timeIntervalSinceDate:currentTime];
secondsLeft = secondsBetween;
[self countdownTimer];
}
- (void)viewDidDisappear:(BOOL)animated
{
[self.timer invalidate];
self.timer = nil;
}
//Initiates timer
- (void)countdownTimer
{
[self.timer invalidate];
self.timer = nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
It's because you are creating new timers without invalidating old ones. The timers don't get invalidated automatically, you have to do it yourself. So if U go on second view and return before your invalidate condition is true you will create new timer and have two of them :)... And so on.

How to make a button appear and disappear throughout a timer

I have this app which has a timer in it and I want to be able to display a button at random points in that timer. Sort Of like a game setting where you have to get the button to get more time before it disappears. I already have some code , but the problem is that the timer that i already have is being messed up ( i can tell because it is linked to a label. It messed up because it goes down by 2 instead of 1 and this only happens when i have the code to make the button appear and disappear with the timer.
Here is the code to my timer that is being messed up:
-(IBAction)Ready:(id)sender {
[self performSelector:#selector(TimerDelay) withObject:nil afterDelay:1.0];
[self performSelector:#selector(randomTimer) withObject:nil afterDelay:0.5];
}
-(void)TimerDelay {
MainInt = 36;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(countDownDuration)
userInfo:nil
repeats:YES];
}
Here is the code to the button:
-(IBAction)Ready:(id)sender { //the same ready action as above
[self performSelector:#selector(TimerDelay) withObject:nil afterDelay:1.0];
[self performSelector:#selector(randomTimer) withObject:nil afterDelay:0.5];
}
-(void)TimerDelay {
MainInt = 36;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(countDownDuration)
userInfo:nil
repeats:YES];
}
- (void)randomTimer {
NSInteger randomTime = arc4random_uniform(0); //Some number between 0 and 9
timer = [NSTimer scheduledTimerWithTimeInterval:randomTime
target:self
selector:#selector(showButton)
userInfo:nil
repeats:NO];
}
- (void)showButton {
if(self.plus5.hidden == YES) {
self.plus5.hidden = NO;
}
else {
self.plus5.hidden = YES;
}
[self TimerDelay]; //Call random timer function again to run this method at a future random time
}
You are calling "randomTimer" and "TimerDelay" (this should be "timerDelay") one after the other and scheduling and REscheduling "timer".
I think you should reconsider your architecture, here...
EDIT: Use just one timer and let it manage your button.
- (void)somewhereInYourCode
{
shouldShowButton = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timeFired)
userInfo:nil
repeats:YES];
}
- (void)timeFired
{
// Here your countdown and...
if (shouldShowButton) {
NSInteger randomTimeInt = arc4random_uniform(9); // as suggested by Bergasms
float randomTimeFloat = randomTimeInt;
[self performSelector:#selector(showButton) withObject:nil afterDelay:randomTimeFloat];
shouldShowButton = NO;
}
}
This way your timer won't (probably) mess up.
This:
arc4random_uniform() will return a uniformly distributed random number
less than upper_bound.
is one of your problems.
NSInteger randomTime = arc4random_uniform(0); //Some number between 0 and 9
needs to be
NSInteger randomTime = arc4random_uniform(9); //Some number between 0 and 9
I cannot say for the rest of your code. But the line you have will always return 0, which means the random timer will always execute instantly.

NSTimer Class Methods, and Invalidation

If I use:
[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(myMethod) userInfo:nil repeats:YES];
How can I invalidate this, as it's a class method I don't have access to a pointer to it?
You can make something like this:
[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(myMethod:) userInfo:nil repeats:YES];
(note ":" after myMethod)
- (void) myMethod: (id) sender
{
if ([sender isKindOfClass:[NSTimer class]])
{
NSTimer* timer = (NSTimer*) sender;
[timer invalidate];
}
}
It's a class method that returns a timer. You invalidate that timer.

Resources