I am trying to execute a certain block of code every x amount of time, but it seems that all I am doing is executing it during that time. Here's a block of my code.
while (TRUE) {
NSTimer *countDown = [NSTimer
scheduledTimerWithTimeInterval:(x)
target:self
selector:#selector(timerHandle)
userInfo:nil
repeats:YES];
}
Any ideas as to how to do it?
As written, this is an infinite loop, creating an NSTimer every loop iteration.
Try it without the while loop. This should cause [self timerHandle] to be invoked on interval x by a single background thread/timer. The Apple guide to NSTimer usage (including as others point out, how to properly stop your timed task) is here.
Try this: (It will call executeMethod on every 5 sec)
if (![NSThread isMainThread]) {
dispatch_async(dispatch_get_main_queue(), ^{
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(executeMethod)
userInfo:nil
repeats:YES];
});
}
else{
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(executeMethod)
userInfo:nil
repeats:YES];
}
Write the code you want to be executed in executeMethod method. Hope this helps.. :)
Related
I want to my Webservice invoke once every 6 Hours.I am newer in iOS. Please help any help would be apperciated.I am stuck.
You can user NSTimer and schedule it for 6 hours
NSTimer *timer = nil;
timer = [NSTimer scheduledTimerWithTimeInterval:6*60*60 //6 hour
target:self
selector:#selector(performAction)
userInfo:nil
repeats:YES];
you can call using NSTimer. this is automatically called which time you set.
e.g.
NSTimer *timer= [NSTimer scheduledTimerWithTimeInterval:10.0(your time) target:self selector:#selector(someMethod) userInfo:nil repeats:YES];
-(void)someMethod
{
////API called here...
}
In ViewDidLoad
NSTimer *timer = [NSTimer timerWithTimeInterval:360.0 target:self selector:#selector(hideandview) userInfo:nil repeats:YES];
-(void)hideandview
{
////API called here...
}
You should save the last time in prefence (NSUserDefaults) when you make a call.
Whenever the app starts. Start timer and check current time with last saved time and get the difference.
I use this code for stopping NSTimer
[timer invalidate]
timer = nil;
It works fine for the first run. But, after I resume the timer with this code.
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates)
userInfo:nil
repeats:YES];
NSTimer won't stop anymore with [timer invalidate]
It look like multiple instance of timer is running simultaneously. You can do one thing, before start to run a new timer, check for previous instance of timer, and if timer instance is available, then invalidate it. After this start new instance
if(timer)
{
[timer invalidate];
timer = nil;
}
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates)
userInfo:nil
repeats:YES];
In apple's official document they said:
You must send this 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.
If your timer is running on main thread, do this:
[timer performSelectorOnMainThread:#selector(invalidate) withObject:nil waitUntilDone:YES];
If it is on any other thread, lets call the thread myThread, then do this:
[timer performSelector:#selector(invalidate) onThread:myThread withObject:nil waitUntilDone:NO];
Hope this helps.. :)
Just invalidate the timer inside the selector that fires. That will ensure you have a pointer to the correct timer (which is probably why your invalidate call isn't working:
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates:)
userInfo:nil
repeats:YES];
Note the colon after checkNewUpdates:
Then, in your checkNewUpdates: method, do something like this:
- (void)checkNewUpdates:(NSTimer*)timer
{
// do somehting
// Then, check if the criteria for stopping the timer has been met, and invalidate it here.
if( self.shouldStopTimer ) // made up variable, use your own criteria.
{
[timer invalidate];
}
}
I know this doesnt answer your question per-se;
Can I suggest using polling mechanism instead of a timer? Ive had a world of trouble with NSTimers in the past and polling was a good alternative. Ive made a simple one below.
- (void) doPoll {
// do logic here
if (shoudStop) {
return;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, X * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self doPoll];
});
}
This is just a simple example, it does not stop retain cycles If you choose to try this, Yours should.
Hope it helps.
I have gone through many sites but still no answer.
I have a method suppose void xyz(), which will get called automatically from a View Controller after every 3 seconds.
I have no idea what to use, do I have to use NSThread or PerformSelector.
Call this method from ViewDidLoad method.ViewDidLoad will when your view will be appear in iPhone device or Simulator.
[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:#selector(runMethod) userInfo:nil repeats:YES];
-(void)runMethod
{
}
Something like this
-(void)xyz{
[self performSelectorInBackground:#selector(xyz) withObject:nil];
}
- (void)viewDidLoad {
[self performSelector:#selector(xyz) withObject:nil afterDelay:0.3];
}
Use NSTimer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:#selector(xyz) userInfo:nil repeats:YES];
You should use NSTimer as mentioned by #mokujin.
Please visit https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html
I have an NSTimer
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(periodicTimer)
userInfo:nil
repeats:YES];
which does
- (void)periodicTimer
{
NSLog(#"Bang!");
if (timerStart != nil)
[timerLabel setText:[[NSDate date] timeDifference:timerStart]];
}
The problem is that while scrolling a tableview (or doing other tasks) the label doesn't get updated, furthermore, "Bang!" doesn't appear, so I supposed the method doesn't get called.
My question is how to update the label periodically even when the user is playing around with the app interface.
You'll need to add your timer to the UITrackingRunLoopMode to make sure your timer also fires during scrolling.
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:#selector(myTimerAction:) userInfo:nil repeats:YES];
[runloop addTimer:timer forMode:NSRunLoopCommonModes];
[runloop addTimer:timer forMode:UITrackingRunLoopMode];
From:
https://stackoverflow.com/a/1997018/474896
Not sure about this one, but my first guess would be that the main thread on which the interface is being rendered your timer just doesn't get a chance to do anything while its updating the interface.
You could create a new thread with a new run loop for your timer, but that is a bit of an ugly solution maybe. What functionality in your app are you trying to achieve? Maybe we can advise a better strategy than using a timer.
My code is:
-(void) timerRun{...}
-(void) createTimer
{
NSTimer *timer;
timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(timerRun)
userInfo:nil
repeats:YES];
}
viewDidLoad
{
[NSThread detachNewThreadSelector:#selector(createTimmer)
toTarget:self withObject:nil];
...
}
When I debug, the method createTimer runs ok, but the method does timerRun not run?
Just creating a timer doesn't start it running. You need to both create it and schedule it.
You're actually going to have to do slightly more work than that if you want it to run on a background thread. NSTimers attach to NSRunloops, which are the Cocoa form of an event loop. Each NSThread inherently has a a run loop but you have to tell it to run explicitly.
A run loop with a timer attached can run itself indefinitely but you probably don't want it to because it won't be managing autorelease pools for you.
So, in summary, you probably want to (i) create the timer; (ii) attach it to that thread's run loop; (iii) enter a loop that creates an autorelease pool, runs the run loop for a bit and then drains the autorelease pool.
Code will probably look like:
// create timer
timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(timerRun)
userInfo:nil
repeats:YES];
// attach the timer to this thread's run loop
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// pump the run loop until someone tells us to stop
while(!someQuitCondition)
{
// create a autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// allow the run loop to run for, arbitrarily, 2 seconds
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
// drain the pool
[pool drain];
}
// clean up after the timer
[timer invalidate];
You have to schedule a timer for it to run. They get attached to a run loop, which in turn updates the timer as necessary.
You can either change createTimer to
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerRun)
userInfo:nil
repeats:YES];
or add
[[NSRunLoop currentRunLoop] addTimer:timer forModes:NSRunLoopCommonModes];
The method signature that you use in scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: must have an argument for the NSTimer as it passes itself as an argument.
You should change your message signature to:
(void)timerRun:(NSTimer *)timer;
You don't need to do anything with the argument, but it should be there. Also in createTimer the selector will become #selector(timerRun:) as it now accepts an argument:
timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(timerRun:)
userInfo:nil
repeats:YES];