I need to call a method when my app starts and then call the same method every 5 seconds.
My code is pretty simple:
// Call the method right away
[self updatestuff:nil]
// Set up a timer so the method is called every 5 seconds
timer = [NSTimer scheduledTimerWithTimeInterval: 5
target: self
selector: #selector(updatestuff:)
userInfo: nil
repeats: YES];
Is there an option for the timer so it's trigger right away and then every 5 seconds ?
NSTimer's -fire, [timer fire]; is what you're looking for.
That will fire/immediately call the timer dismissing the time delay.
You can't schedule the timer and fire the event immediately all in the same line of code. So you have to do it in 2 lines of code.
First, schedule the timer, then immediately call 'fire' on your timer:
timer = [NSTimer scheduledTimerWithTimeInterval: 5
target: self
selector: #selector(updatestuff:)
userInfo: nil
repeats: YES];
[timer fire];
When fire is called, the time interval that your timer waits to fire will reset because it just ran, and then will continue to run thereafter at the designated interval--in this case, every 5 seconds.
In Swift:
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(foo), userInfo: nil, repeats: true)
timer.fire()
You can initialise the timer and fire it in the same line:
[(checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:#selector(checkStatusTimerTick:) userInfo:nil repeats:YES]) fire];
In swift this can be achieved in one line like:
Timer.scheduledTimer(withTimeInterval: intervalInSec, repeats: true) {
}
Related
I have NSTimer and Action for it. But I want to call Action after 5s for first time, 4s for second time and ... .
_timepast = 6;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(handleDelay) userInfo:nil repeats:YES];
-(void)handleDelay
{
_timepast = _timepast - 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timepast * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self handleTimer];
});
}
First of all if you want to start action after 5 sec and then create first timer which trigger after 5 sec delay and then invalidate first timer and start your second timer with countDown of 5. It means after 5 sec delay you will your selector called and handle action in it. I am giving you code for how second timer works. I hope you will know how to handle first timer for 5 sec delay.
Create 2 variable
var timerCount = 5
var timer : Timer!
Create timer of 1 sec interval
timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(self.startTimer), userInfo: nil, repeats: true)
In the selector method write reverse checking like,
func startTimer() {
if timerCount > 0 {
label.text = String(timerCount--)
}
else {
timer.invalidate()
}
}
I am having a NSTimer in my VC and its working fine its sending location of user and i cant invalidate it on viewDidDisappear as i need to send in background also.
myTimer=[NSTimer scheduledTimerWithTimeInterval:2.0 target: self
selector: #selector(sendDataToSocket) userInfo: nil repeats: YES];
But the issue is when i instantiate same VC again it start the NSTimer again and 2 timers are working. so how can i stop the previous one or any other solution
Any help will be appreciated
Thanks
you should handle the timer instantiation mechanism in your AppDelegate
so, in your ViewController, every time you instantiate it, you can call
[((YourAppDelegate*)[UIApplication sharedApplication].delegate) startMyTimer:self];
where startMyTimer could be defined like this
-(void)startMyTimer:(id)aTarget
{
if(myTimer)
{
[myTimer invalidate];
myTimer = nil;
}
myTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: aTarget
selector: #selector(sendDataToSocket)
userInfo: nil
repeats: YES];
}
so you are sure that only one myTimer is always active in your app and you can call your ViewController's sendDataToSocket
You can use the singleton class or simple use the appDelegate class to just declare the myTimer object in appDelegate and use it in your viewController.
This will have a single object of timer and you dont need to create multiple objects and your ultimate objective will be resolved. Hope this Helps!
I add timer like this
tim=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(repeatTim) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:tim forMode:NSDefaultRunLoopMode];
tim it is NSTimer property of my class.
Then i stop it on button click like
[[fbt tim] invalidate];
[fbt setTim:nil];
fbt it is instance of my class.
if i call only invalidate then it doesn't stop, but if i set it to nil then i got EXC_BREAKPOINT
here code of repeatTim method in selector
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
[appDelegate.wbv stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"intal()"]];
I tried to call init and invalidate in
dispatch_async(dispatch_get_main_queue(), ^{})
it also doesn't stop timer.
You have more than one timer running . Try this:
-(void)startTimer{
[self.myTimer invalidate]; // kill old timer
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(doSomething) userInfo:nil repeats:YES];
}
-(void)stopTimer{
[self.myTimer invalidate];
self.myTimer=nil; //set pointer to nil
}
Read documentation for NSTimer:
There are three ways to create a timer:
Use the scheduledTimerWithTimeInterval:invocation:repeats: or scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer and schedule it on the current run loop in the default mode.
Use the timerWithTimeInterval:invocation:repeats: or timerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer object without scheduling it on a run loop. (After creating it, you must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop object.)
Allocate the timer and initialize it using the initWithFireDate:interval:target:selector:userInfo:repeats: method. (After creating it, you must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop object.)
You are using method which already adds it to mainLoop from 1. - you need to remove this line or create a timer with 2. approach and leave manual adding.
Also 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.
I have tried every possible solution found but not able to resolve that at the end I have set repeat "false" while initialising timer like below
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(viewcontroller.methodname), userInfo: nil, repeats: false)
And need to add above line in my selector method for whatever the condition for which I wanted to repeat the time.
For example:- My requirement is I want to repeatedly call some method until one condition satisfied. So instead of adding repeats true I set it false as repeat true does not invalidate timer in my case.
I have added below in my viewdidload method
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(viewcontroller.method), userInfo: nil, repeats: false)
in selector function I added below code:-
func method{
if condition matched{
// here your timer will be invalidated automatically
}
else{
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector: #selector(viewcontroller.method), userInfo: nil,repeats: false)
}
}
Hope this will solve your problem.
Happy Coding :)
I've created a test application with timer before implementing it in my project.
It was the first time I'm using timer.
But the issue is when I implemented timer using [NSTimer timerWithTimeInterval: target: selector: userInfo: repeats: ]; , it is not working.
Here is my code,
Interface:
#interface uialertViewController : UIViewController
{
NSTimer *timer;
}
-(void)displayAlert;
-(void)hideandview;
#end
Implementation:
#implementation uialertViewController
- (void)viewDidLoad {
[self displayAlert];
[super viewDidLoad];
}
-(void)displayAlert{
timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(hideandview) userInfo:nil repeats:NO];
alert = [[UIAlertView alloc] initWithTitle:#"testing" message:#"hi hi hi" delegate:nil cancelButtonTitle:#"continue" otherButtonTitles:nil];
[alert show];
[alert release];
alert = nil;
}
-(void)hideandview{
NSLog(#"triggered");
[alert dismissWithClickedButtonIndex:0 animated:YES];
[alert release];
[self displayAlert];
}
#end
Then I Changed [NSTimer timerWithTimeInterval: target: selector: userInfo: repeats: ]; with [NSTimer scheduledTimerWithTimeInterval: target: selector:userInfo: repeats: ]; , It is working. What was the issue with timerWithTimeInterval: ? Am I mising anything in my first implementation ? Thanks in advance.
scheduledTimerWithTimeInterval:invocation:repeats: and scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: create timers that get automatically added to an NSRunLoop, meaning that you don't have to add them yourself. Having them added to an NSRunLoop is what causes them to fire.
With timerWithTimeInterval:invocation:repeats: and timerWithTimeInterval:target:selector:userInfo:repeats:, you have to add the timer to a run loop manually, with code like this:
[[NSRunLoop mainRunLoop] addTimer:repeatingTimer forMode:NSDefaultRunLoopMode];
Other answers on here suggest that you need to call fire yourself. You don't - it will be called as soon as the timer has been put on a run loop.
Also one may want to make sure to add timer on the main thread.
assert(Thread.isMainThread)
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(YourSelector), userInfo: nil, repeats: true)
As a previous answer noted schedule on the main thread, but rather than using assert, put it on the main thread:
#objc func update() {
...
}
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
And if async is not desired, try this:
let schedule = {
self.timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
if Thread.isMainThread {
schedule()
}
else {
DispatchQueue.main.sync {
schedule()
}
}
The difference between the two is that the timerWithTimeInterval method returns a NSTimer object that has not yet been fired. To fire the timer you have to use [timer fire]; On the other hand the scheduledTimerWithTimeInterval returns an NSTimer that has already been fired.
So, in your first implementation you were just missing [timer fire];
I have the following code:
timer = [[NSTimer scheduledTimerWithTimeInterval:0.50 target:self selector:#selector(onTimer) userInfo:nil repeats:YES] retain];
-(void) onTimer
{
}
After every 0.50 seconds the OnTimer method is called.
But now I want to increment the time-interval.
That means:
OnTimer calls after 0.55
OnTimer calls after 0.60
OnTimer calls after 0.65
OnTimer calls after 0.70
OnTimer calls after 0.75
& so on.
Is there any solution for this?? I have tried lot but its not working.
Sure you can do this. Change repeats:YES to repeats:NO so that the timer doesn't repeat, and then in onTimer, just start a new timer with a longer interval. You need a variable to hold your interval so that you can make it a bit longer each time through onTimer. Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.
I'm no Objective-C expert (or iOS expert...) and it's been a while but I think something like this:
float gap = 0.50;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
}
Something like that? Oh, and I'm really not too sure about the retain semantics here... read the docs to make sure you don't leak!
Here is one solution to Hardik's question using NSTimer's fireDate property (written in Swift):
Swift 2
var timeInterval = 0.50
NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("onTimer:"), userInfo: nil, repeats: true)
func onTimer(timer: NSTimer) {
timeInterval += 0.05
timer.fireDate = timer.fireDate.dateByAddingTimeInterval(timeInterval)
}
Swift 3, 4, 5
var timeInterval = 0.50
Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(self.onTimer), userInfo: nil, repeats: true)
#objc func onTimer(timer: Timer) {
timeInterval += 0.05
timer.fireDate = timer.fireDate.addingTimeInterval(timeInterval)
}
You could try adjusting the timer's FireDate, see setFireDate
You can't change the interval at which a timer fires. No way. There's no API for doing this.
Two obvious workarounds: If you always change the interval, then you can just change the next time that the timer fires; this has precedence over the timer interval. Of course you have to do that every time the timer fires. If you sometimes change the interval, just invalidate the first timer and create a new timer with the new interval.
This just work like charm for me.
- (void)FlexibleTimer {
if (!keyTimer) {
keyTimer = [NSTimer scheduledTimerWithTimeInterval:self.intervalOfIdleTimer
target:self
selector:#selector(keyTimerExceeded)
userInfo:nil
repeats:YES];
}
else {
if (fabs([keyTimer.fireDate timeIntervalSinceNow]) < self.intervalOfIdleTimer - 1.0) {
[keyTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:self.intervalOfIdleTimer]];
}
}
}
- (void)keyTimerExceeded {
[self setNextDelayForFlexibleTimer];
[self FlexibleTimer];
NSLog(#"Timer Exceeded %f", [[NSDate date] timeIntervalSince1970]);
}