Why NSTimer sends positions every 5 seconds instead of every 60? - objective-c

Why NSTimer sends positions every 5 seconds instead of every 60?
- (void)startTimer {
self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:#selector(sendPosition)
userInfo:nil
repeats:YES];
}
- (void)stopTimer {
if(self.timer){
[self.timer invalidate];
self.timer = nil;
}
}

I suspect that there are multiple timers created due to multiple firing of startTimer function. To ensure that there is only one instance of such timer, you can implement the following.
- (void)startTimer {
// stop and remove timer first if it is already there
if(self.timer){
[self.timer invalidate];
self.timer = nil;
}
self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:#selector(sendPosition)
userInfo:nil
repeats:YES];
}
This way, no matter how many times the startTimer was called,there is only one instance of it.

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];
}

Objective C : NStimer- How to stop timer after n hours

I have started the timer using below call, and need to stop it after n hours
self.timer = [NSTimer scheduledTimerWithTimeInterval:20 target:self selector:#selector(sendLocationUpdates) userInfo:nil repeats:YES];
The solution I can thin of get the current time when timer start and keep adding time till threshold reaches. Or is there any better way to stop timer?
Add an instance variable to the class to store the start time of the timer:
YourClass.m:
#interface YourClass () {
NSTimeInterval _startTime;
}
#end
Record the current time when creating the timer:
self.timer = [NSTimer scheduledTimerWithTimeInterval:20 target:self selector:#selector(sendLocationUpdates) userInfo:nil repeats:YES];
_startTime = [NSDate timeIntervalSinceReferenceDate];
and test the current time in the sendLocationUpdates method:
#define TIMER_LIFE_IN_SECONDS 3000.0
- (void)sendLocationUpdates
{
// do thing
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
if (now - _startTime > TIMER_LIFE_IN_SECONDS) {
[self.timer invalidate];
self.timer = nil;
}
}
simple solution
declare two properties
#property NSInteger counter;
#property NSTimeInterval interval;
set the counter to 0 before starting the timer
self.counter = 0;
self.interval = 20.0;
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval target:self selector:#selector(sendLocationUpdates) userInfo:nil repeats:YES];
in the sendLocationUpdates method increment the counter
- (void)sendLocationUpdates
{
counter++;
if (counter == 4 * (3600 / self.interval)) {
[self.timer invalidate];
self.timer = nil;
}
// do other stuff
}
with a given time interval of 20 seconds the timer fires 180 times per hour.
In the example the timer stops after 4 hours

Stop immediately NSTimer

I'm trying to stop my NSTimer (no repeats) immediately but i can't.
my NSTimer do the following code:
-(void)timerAction:(NSTimer*)timer{
dispatch_queue_t serverDelaySimulationThread = dispatch_queue_create("com.xxx.serverDelay", nil);
dispatch_async(serverDelaySimulationThread, ^{
[NSThread sleepForTimeInterval:2.0];
dispatch_async(dispatch_get_main_queue(), ^{
//CALL WEBSERVICE RESPONSE IN HERE
});
});
}
Each time textField Did Change, i will invalidate NSTimer and recreate NSTimer!! All i want to execute a request to WEBSERVICES if the Delay time between 2 times user typing characters bigger than 2s. My code is following
-(void) textFieldDidChange:(id)sender{
[MyTimer invalidate];
MyTimer = nil;
MyTimer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:#selector(timerAction:) userInfo:nil repeats:NO];
}
But, when i quickly type "ABCD" -> 2s after that, 4 webservices was called.
How can i stop NSTimer while it unfinished
Tks for advance!
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
[myTimer invalidate];
myTimer = nil;
myTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(timerFired) userInfo:nil repeats:NO];
return YES;
}
This worked for me.
Your timer timeInterval is set to 0. So each time you type your timer fires. Change your code to look like this
MyTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self selector:#selector(timerAction:) userInfo:nil repeats:NO];
And it should work :)
The problem is you are implementing textdidchange delegate. So how many times you type text. It will get called. SO inside that you have written four letters. So definitely your NSTimer is calling four times your web service. I would suggest better to use - (void)controlTextDidEndEditing:(NSNotification *)aNotification So that whenever you enter or tabb out your webservice will called.

How to run NSTimer until flag variable ON in Cocoa

I have a problem: I want to NSTimer waiting until FLAG variable is YES, if FLAG = YES, myTimer is stop. How can i do that? I tried below code:
NSTimer *myTimer;
int delay = 6.0;
scanTimer= [NSTimer scheduledTimerWithTimeInterval:6.0 target:self selector:#selector(anotherfunc) userInfo:nil repeats:YES];
myTimer= [NSTimer timerWithTimeInterval: delay
target:self
selector: #selector(resetAll:) userInfo:nil
repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSModalPanelRunLoopMode];
[[NSApplication sharedApplication] runModalForWindow: scanningPanel];
This is resetAll () function :
-(void) resetAll: (NSTimer *) theTimer
{
if(FLAG)
{
NSLog(#"killWindow");
[[NSApplication sharedApplication] abortModal];
[scanningPanel orderOut: nil];
FLAG = NO;
}
else
{
delay +=6.0;
myTimer= [NSTimer timerWithTimeInterval: delay
target:self
selector: #selector(resetAll:) userInfo:nil
repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSModalPanelRunLoopMode];
[[NSApplication sharedApplication] runModalForWindow: scanningPanel];
}
}
I used 2 NSTimer, but only myTimer run, scanTimer not run. Please give me any suggestions. Thanks in advance
Why not use Key Value Observing for the FLAG change? Add the flag variable as a property of the class you're working in:
#property(nonatomic, assign) BOOL flag;
To avoid repetition place in your .m:
#define kFooFlagKey #"flag"
Override -setFlag: so it is KVO compliant:
-(void)setFlag:(BOOL)flag
{
if (_flag == flag) {
return;
}
[self willChangeValueForKey:kFooFlagKey];
_flag = flag;
[self didChangeValueForKey:kFooFlagKey];
}
In the class' initializer add self as the observer for the keypath you'd like to monitor. In this case it will be for the property "flag".
[self addObserver:self
forKeyPath:kFooFlagKey
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:NULL];
Don't forget to remove the observer in the class' -dealloc:
[self removeObserver:self forKeyPath:kFooFlagKey];
Create the timer to fire repeatedly (firingCallBack is a method called with each fire):
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.0f
target:self
selector:#selector(firingCallBack)
userInfo:nil
repeats:YES];
Implement KVO observing method:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqualToString:kFooFlagKey]) {
if (self.flag) {
[self performSelector:#selector(resetAll) withObject:nil afterDelay:0.0f];
}
}
}
Implement -resetAll however you'd like. It will be called when you are setting the flag variable via the accessor AND the flag is set to YES
Try like this:-
NSTimer *myTimer;
int delay = 6.0;
scanTimer= [NSTimer scheduledTimerWithTimeInterval:6.0 target:self selector:#selector(anotherfunc) userInfo:nil repeats:YES];
myTimer= [NSTimer scheduledTimerWithTimeInterval: delay
target:self
selector: #selector(resetAll:) userInfo:nil
repeats:NO];
[NSApp beginSheet:scanningPanel modalForWindow:[self window]
modalDelegate:self
didEndSelector:nil
contextInfo:self];
- (void)resetAll:(NSTimer *)theTimer
{
if (flag== YES)
{
[NSApp endSheet:scanningPanel];
[scanningPanel orderOut:self];
flag=NO;
}
else
{
delay +=6.0;
myTimer= [NSTimer scheduledTimerWithTimeInterval: delay
target:self
selector: #selector(resetAll:) userInfo:nil
repeats:NO];
[NSApp beginSheet:scanningPanel modalForWindow:[self window]
modalDelegate:self
didEndSelector:nil
contextInfo:self];
}
}
You just start the timer (already scheduled) and make it repeat at a relatively high frequency and stop it when the condition is met. One timer can act as two, like this:
- (void)startTimers {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
}
- (void)timerFired:(NSTimer *)timer {
if (self.stopTimerA && self.stopTimerB) {
[timer invalidate];
} else {
if (!self.stopTimerA)
[self timerAFired];
if (!self.stopTimerB)
[self timerBFired];
}
}
- (void)timerAFired {
// this can be coded like it has it's own timer
// we didn't pass the timer, so we can't invalidate it
// to stop...
self.stopTimerA = YES;
}
- (void)timerBFired {
// same idea here
}

How to pass an argument to a method called in a NSTimer

I have a timer calling a method but this method takes one paramether:
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:#selector(timer) userInfo:nil repeats:YES];
should be
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:#selector(timer:game) userInfo:nil repeats:YES];
now this syntax doesn't seems to be right. I tried with NSInvocation but I got some problems:
timerInvocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(timer:game)]];
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
invocation:timerInvocation
repeats:YES];
How should I use Invocation?
Given this definition:
- (void)timerFired:(NSTimer *)timer
{
...
}
You then need to use #selector(timerFired:) (that's the method name without any spaces or argument names, but including the colons). The object you want to pass (game ?) is passed via the userInfo: part:
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
target:self
selector:#selector(timerFired:)
userInfo:game
repeats:YES];
In your timer method, you can then access this object via the timer object's userInfo method:
- (void)timerFired:(NSTimer *)timer
{
Game *game = [timer userInfo];
...
}
As #DarkDust points out, NSTimer expects its target method to have a particular signature. If for some reason you can't conform to that, you can instead use an NSInvocation as you suggest, but in that case you need to fully initialise it with the selector, target and arguments. Eg:
timerInvocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(methodWithArg1:and2:)]];
// configure invocation
[timerInvocation setSelector:#selector(methodWithArg1:and2:)];
[timerInvocation setTarget:self];
[timerInvocation setArgument:&arg1 atIndex:2]; // argument indexing is offset by 2 hidden args
[timerInvocation setArgument:&arg2 atIndex:3];
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
invocation:timerInvocation
repeats:YES];
Calling invocationWithMethodSignature on its own doesn't do all that, it just creates an object that is able to be filled in in the right manner.
You can pass NSDictionary with named objects (like myParamName => myObject) through userInfo parameter like this
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
target:self
selector:#selector(timer:)
userInfo:#{#"myParamName" : myObject}
repeats:YES];
Then in timer: method:
- (void)timer:(NSTimer *)timer {
id myObject = timer.userInfo[#"myParamName"];
...
}