Managing Timers Passed as Variables - ios

I am trying to perform what I thought was a simple task. I have a handful of repeating timers that need to be started and stopped.
I created methods for starting and stopping the timers, and attempt to pass the timers to the methods as parameters.
The problem is that the timers never seem to be stopped. Any ideas why this might not be working properly? Thank you!
Top of File:
#import "ViewController.h"
NSTimer *launchTimer;
NSTimer *transactionTimer;
Starting Method:
-(void) startingMethod {
NSString *urlString = #"http://google.com";
[[AsynchRequestService sharedInstance]
performAsynchronousURLRequest:urlString completion:^(BOOL success,
NSString *responseBody, NSString *responseStatus) {
if (success) {
[self stopResponseTimer:launchTimer];
}
else {
[self startResponseTimer:launchTimer
method:#selector(startingMethod)
interval:10];
}
}];
}
Method to Start the Timer:
-(void)startResponseTimer:(NSTimer *) timer method:(SEL) method
interval:(int) interval {
[timer invalidate];
timer = nil;
timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self
selector:method userInfo:nil repeats:YES];
}
Method to Stop the Timer:
-(void)stopResponseTimer:(NSTimer *) timer {
NSLog(#"STOP TIMER");
[timer invalidate];
timer = nil;
}

Make startResponseTimer and `stopResponseTimer' take the pointer to the object pointer intead.
-(void)startResponseTimer:(NSTimer **) timer method:(SEL) method
interval:(int) interval {
[*timer invalidate];
*timer = nil;
*timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self
selector:method userInfo:nil repeats:YES];
}
-(void)stopResponseTimer:(NSTimer **) timer {
NSLog(#"STOP TIMER");
[*timer invalidate];
*timer = nil;
}
then invoke it like
[self startResponseTimer:&launchTimer];
[self stopResponseTimer:&launchTimer];
This should make sure that you retain the right NSTimer object.
NOTE:It is always a good idea to check a pointer to a pointer to an object for NULL in a public method

Related

iOS: Why can I not call performSelector to execute the same function where it is called?

When I use [self performSelector:#selector(checkFirstSynchro) withObject:nil afterDelay:30.0]; in the checkFirstSynchro function, it seems not to work. Is it because it is in a Class function?
-(void) viewDidLoad
{
...
[self checkFirstSynchro]
...
}
- (void) checkFirstSynchro
{
//Check if firstSynchro
BOOL firstSynchro = [[[NSUserDefaults standardUserDefaults] valueForKey:#"FirstSynchro"] boolValue];
if (!firstSynchro)
{
[Reachability checkInternetConnectivityWithSuccessCompletion:^(NSError *error) //test if there is internet c
onnection
{
if (error == nil)
{
[self sync:connectBtn];
}
else
{
[self performSelector:#selector(checkFirstSynchro) withObject:nil afterDelay:30.0];
}
}];
}
}
It launches well the function, but it doesn't execute the perform 30.0 seconds later.
I tried this instead of the performSelector, but without success:
[NSTimer scheduledTimerWithTimeInterval:TIMER_FIRST_SYNCHRO
target:self
selector:#selector(checkFirstSynchro)
userInfo:nil
repeats:NO];
It launches well the function, but it doesn't execute the [NSTimer scheduledTimerWithTimeInterval 30.0 seconds later.
Thanks in advance.

UIProgressView not updating for Audio Player?

The ProgressView is not updating while playing the song. By reading from other post i have used an update method to update at each time interval.
- (void)viewDidLoad {
[super viewDidLoad];
NSString *filePath = [[NSBundle mainBundle]pathForResource:#"Fix you_Coldplay" ofType:#"mp3" inDirectory:#"Coldplay"];
NSLog(#"%#",filePath);
NSURL *url = [NSURL fileURLWithPath:filePath];
NSLog(#"%#",url);
musicPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
[musicPlayer prepareToPlay];
[trackProgress setProgress:0.0];
}
I have a play button which is also being used for calling updateTime: method.
- (IBAction)playButton:(id)sender {
[musicPlayer play];
[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
NSTimeInterval interval = musicPlayer.currentTime/musicPlayer.duration;
NSLog(#"%f",interval);
}
The updateTime: method
-(void)updateTime:(NSTimer *)timer {
trackProgress.progress = (musicPlayer.currentTime/musicPlayer.duration);
}
I am very new to programming and even stack overflow. This is the first question i am posting. Please help me and Thanks in advance.
First of all change timer value to:
//Change Value to 0.5 or 1 sec
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
Make sure you are setting trackProgress as 0 as initial value.
- (void)viewDidLoad {
[super viewDidLoad];
trackProgress.progress = 0.0;
}
Hope this will resolve your issue.
Make sure to update the progress view on the main thread
-(void)updateTime:(NSTimer *)timer {
dispatch_async(dispatch_get_main_queue(), ^{
self.trackProgress.progress = (musicPlayer.currentTime/musicPlayer.duration);
});
}
This might help. Create a Timer and add it to common runloop as shown below. Also keep a reference to timer so that it can be stopped later.
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

IOS - Objective C - How to stop executing periodic function when exiting the view?

I have a function in one of my viewControllers that I execute once every 10 seconds.
I want this function to stop it's execution when I exit the view.
I tried this peace of code :
-(void)viewWillDisappear:(BOOL)animated
{
NSError *error2;
if ([_managedObjectContext save:&error2] == NO) {
NSAssert(NO, #"Save should not fail\n%#", [error2 localizedDescription]);
abort();
}
else
NSLog(#"Context Saved");
[self stopTimer];
NSLog(#"View will disappear now");
}
It is basicly calling the method stopTimer that will give a value of null to the timer.
- (void) stopTimer
{
[timer invalidate];
timer = nil;
}
My problem is that my function keeps on executing even if I get out of my view. and never stops. How can I fix this?
EDIT:
This is the function called by my nstimer:
- (void) MyFunctionCalledByNSTimer
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self selector:#selector(Function1) userInfo:nil repeats:YES];
}
I declare my nstimer in .m of my viewController
NSTimer *timer;
If you need more peaces of code just ask and I will edit the question.
May be issue happening because of creating more than one timer and invalidating only what you have reference to.
So, may be modifying MyFunctionCalledByNSTimer like below will solve your problem:
- (void) MyFunctionCalledByNSTimer
{
if(!timer){
timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self selector:#selector(Function1) userInfo:nil repeats:YES];
}
}
Now, only one timer reference will be there and [timer invalidate] will invalidate timer.
Use this code
call stopTimer on main thread
-(void)viewWillDisappear:(BOOL)animated
{
NSError *error2;
if ([_managedObjectContext save:&error2] == NO) {
NSAssert(NO, #"Save should not fail\n%#", [error2 localizedDescription]);
abort();
}
else
NSLog(#"Context Saved");
dispatch_async(dispatch_get_main_queue(), ^{
//Your main thread code goes in here
[self stopTimer];
});
NSLog(#"View will disappear now");
}
remember that you must send invalidate message from the thread on which the timer was installed. If you send this message from another thread, the input source associated with the timer may not be removed from its run loop, which could prevent the thread from exiting properly.

how to make NSTimer consistent on xcode

I'm making a game and would like to use a timer to countdown an event, just like what's seen on Bejeweled. I know that I've to put NSTimer in a NSRunLoop to make it work, since NSTimer is inaccurate. Have tried the following but it still don't work. Please help!
#import ...
NSTimer *_gameTimer;
int secondsLeft;
//some code
//called countdownTimer using [self countdownTimer];
- (void)countdownTimer
{
_gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
NSRunLoop *gameRun = [NSRunLoop currentRunLoop];
[gameRun addTimer:_gameTimer forMode:NSDefaultRunLoopMode];
}
- (void)updateTime:(NSTimer *)timer
{
if (secondsLeft>0 && !_gameOver) {
_timerLabel.text = [NSString stringWithFormat:#"Time left: %ds", secondsLeft];
secondsLeft--;
} else if (secondsLeft==0 && !_gameOver) {
// Invalidate timer
[timer invalidate];
[self timerExpire];
}
}
- (void)timerExpire
{
// Gameover
[self gameOver];
[_gameTimer invalidate];
_gameTimer = nil;
}
NSTimer needs to be a local variable so there can only be one instance of the object running through the loop. Here's the code.
- (void)countdownTimer
{
NSTimer *_gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
NSRunLoop *gameRun = [NSRunLoop currentRunLoop];
[gameRun addTimer:_gameTimer forMode:NSDefaultRunLoopMode];
if (secondsLeft==0 || _gameOver) {
[_gameTimer invalidate];
_gameTimer = nil;
}
}
- (void)updateTime:(NSTimer *)timer
{
if (secondsLeft>0 && !_gameOver) {
_timerLabel.text = [NSString stringWithFormat:#"Time left: %ds", secondsLeft];
secondsLeft--;
} else if (secondsLeft==0 || _gameOver) {
// Invalidate timer
[timer invalidate];
[self timerExpire];
}
- (void)timerExpire
{
// Gameover
[self gameOver];
}

Stop gyro updates

I cant work out to stop the Gyro updates in my Cocos2D game,
I have got the following code in my init: ` //gyro
motionManager = [[CMMotionManager alloc] init];
referenceAttitude = nil;
[motionManager startGyroUpdates];
timer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:#selector(doGyroUpdate)
userInfo:nil
repeats:YES];
Then in the gyro update itself I check when the progress is more than 100% if (progress > 100) {
[self pauseSchedulerAndActions];
[self stopGyroUpdates];
Then:
- (void)stopGyroUpdates{
NSLog(#"Stop gyro update");
}
but it keeps checking... So the code within the if statement keeps getting called.
I found the solution with the following code: `
-(void) callgyro:(int)gyroprocess {
NSLog(#"%i", gyroprocess);
if (gyroprocess < 100 ) {
motionManager = [[CMMotionManager alloc] init];
referenceAttitude = nil;
[motionManager startGyroUpdates];
timertwee = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:#selector(doGyroUpdate)
userInfo:nil
repeats:YES];
}
else {
[motionManager stopGyroUpdates];
[timertwee invalidate];
NSLog(#"Gyro moet stoppen!");
}`
and within the gyro update itself:
if (progress > 100) {
[self callgyro:progress];
[self.timer invalidate];
self.timer = nil;
[Blikje setImage:[UIImage imageNamed:#"pop3.png"]];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setFloat:numhundreds forKey:#"score"];
progress = 0;
[self stopGyroUpdates];
}
Like rickster said, you need to call stopGyroUpdates on the CMMotionManager instance.so you need to create an instance variable or property in the interface implementation.
In your .m file where your declare the interface:
#interface ViewController ()
#property (strong, nonatomic) CMMotionManager *motionManager;
#end
Then initialize it as you require
motionManager = [[CMMotionManager alloc] init];
Then when you need to stop updates you call
[self.motionManager stopGyroUpdates]
You need to call stopGyroUpdates on your instance of CMMotionManager, not (or in addition to) on self. (This means that instance needs to persist beyond the scope if the method in which you call startGyroUpdates -- say, in a property or ivar -- if it doesn't already.)

Resources