NSTimer is pausing a while an then again it is starting when UIGesture action performed.
I am developing an iOS application where I have to trigger the NSTimer repeatedly for every 0.5 seconds and based on that timer I'm moving a song progress bar. And also handling touch events when user touching on some images which I kept on the same view. I am seeing when user touches the images, the timer for moving the progress bar is stopping a little while and continues again.
Are there any problem that we can't handle timer and touch events at the same time in the same view?
My code for timer
myTimer = [NSTimer scheduledTimerWithTimeInterval:timeinterval target:self selector:#selector(updatplayer:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
This is a common issue with NSTimer. While you can play with run loop modes to improve things, a nicer solution is to switch to GCD timers. See RNTimer for an example. See the docs on dispatch_source_create for more information.
Related
When does an NSTimer fire if the main thread is busy? Here is the line of code in question:
[NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(onTimer:)
userInfo:nil
repeats:YES];
I'm a bit new to NSTimer (and run loops and threads) so thank you for the help. My app does a refresh on an NSTimer that was scheduled on the main thread. There may be issues if the refresh timer fires at the exact time interval specified and does not wait for the main thread to free up.
An example would be if the user does some action on the screen that is linked to data, and then the refresh fires immediately after and changes that data, causing the app to crash. Is this likely to happen, or will the refresh not fire until the users action has been resolved on the main thread?
NSTimer schedules the timer on the current run loop (i.e. main run loop in this example) and so if the main thread is busy, the timer won't fire until you yield back to the main run loop.
See Timer Programming Topics and the NSTimer Class Reference, for more information.
Im developing an app that has to run in the background. It's a location based app, so it runs all the time, the OS doesn't kill it.
It should send some info every 10 secs(just for debugging), I set a timer once its in the background. I set a breakpoint in the function that should be executed every 10 secs, which is never called, but if I pause the app and then continue the timer is called, and then the timer is executed every 10 secs without problems, weird right?
I thought that the timer would be executing anyway when I wasn't debugging, but it isn't, same thing as if I didn't pause the debugging.
My question is WHY?? The timer is set correctly(I assume) since it works after pausing, but it's not.
Any ideas?
The way I set the timer is:
self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(doStuff) userInfo:nil repeats:YES];
And in the function I connect to a webservice.
Thanks.
I have a similar app design and was stuck on the same thing. What I found somewhere on the internet is adding this type of statement applicationDidEnterBackground:
UIBackgroundTaskIdentifier locationUpdater =[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:locationUpdater];
locationUpdater=UIBackgroundTaskInvalid;
} ];
This tells the os that you still have things going and not to stop it.
I have my timer attached to this function
//this is a wrapper method to fit the required selector signature
- (void)timeIntervalEnded:(NSTimer*)timer {
[self writeToLog:[NSString stringWithFormat:#"Timer Ended On %#",[NSDate date]]];
[self startReadingLocation];
[timer invalidate];
timer=nil;
}
I set the timer in my my location manager delegate methods.
I feel your pain. I found that these things were super finicky. This is what worked for me. I hope it helps. I have found that there isn't any really restrictions in what you can do in the background.
There might be restrictions on what you can do in the background. Try adding the timer to the run loop before going into the background. Even that might not work; it may be that the only code of yours that can run in the background is the code called by the Core Location methods you've signed up for (e.g. locationManager:didUpdate...). But my impression is that timers already running before you start to go into the background will continue to run.
I have a repeated timer with interval of 1/4 second. I am initializing it like this:
[NSTimer scheduledTimerWithTimeInterval:0.25
target:self
selector:#selector(toggleCams)
userInfo:nil
repeats:YES];
Does this happen synchronously? In other words, am I guaranteed that another method in the same class will not be called at the same time toggleCams is called?
The NSTimers actually just periodically fire events into the enclosing NSRunLoop, which each thread has (or should have). So, if you have a child (or background) process running in a different thread, the NSTimers will fire against that thread's NSRunLoop instead of the application's main NSRunLoop.
For some reason when I push down (click and hold) on any control, the NSTimer in my App freezes and does not fire until I release the mouse button. It simply does not fire while I have the mouse pressed. This is fine for short periods, but it also freezes if I have a popup menu open, or a combobox dropped down.
I'm not sure if there is something I missed, but it seems like this is incorrect behavior.
I want to be able to click the down arrow of an NSPopUpButtonCell (or even click and hold an NSTableView) without the entire NSTimer freezing (which redraws an NSView).
Any comments / suggestions would be appreciated.
The NSTimer is added to the currentRunLoop with mode NSDefaultRunLoopMode.
While the mouse is down, the run loop is in the NSEventTrackingRunLoopMode. Therefore, any event that's not received onto the EventTracking event queue won't be serviced until the runloop returns to the appropriate mode.
The way around this is to add the timer to the runloop for both modes (default and event tracking).
Instead of adding two or more timers to different runloops or using multithreading (as you won't then be able to update the UI from another thread) simply add the timer to the NSRunLoopCommonModes:
NSTimer *myTimer = [NSTimer timerWithTimeInterval:RefreshInterval target:self selector:#selector(doWork) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
Assuming you're just dealing with one thread in your application, what you described is perfectly expected. By default, NSTimer's are added to the current NSRunLoop which, in your case, is also responsible for dealing with UI interaction. When it gets tied up with handling UI interaction, it can't check your timer and "fire" it.
A solution is to use multi-threading so as to avoid this tie-up. Here's a nice blog post on this very subject: http://blog.narent.com/?p=21
EDIT: See Dave's post for an alternative (and more elegant IMO) solution
Also see:
NSTimer doc
NSRunLoop doc
Threading programming guide
I'm currently using the snippet of code presented below to fire some methods every second. My app is running in the background. The problem is that if the computer wakes up after a sleep period the timer wants to retroactively fire all the methods it has missed. Similar issues come up if the user were to change the System Clock time.
Basically I want to implement the proper timer method that will have my methods called only every current second. If a second (or minute or hour or day) has passed and for whatever reason the methods weren't called I want my app to just continue from the current moment in time.
Also, can we keep this while using NSTimer?
Thanks!
-(void)start
{
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(tasks:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode];
}
To handle the big time changes you can use the link UIApplicationSignificantTimeChangeNotification and unregister/reregister your timer.
To deal with the sleep issue, you can unregister and then reregister your timer whenever the machine goes to sleep and wakes up. See this technical note for information on how to do that. This solution won't work for changing the system time, though.