When Does NSTimer Fire If Main Thread Is Busy? - objective-c

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.

Related

NSTimer is pausing a while when UIGesture action performed

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.

How to exit NSTimer? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSTimer doesn't stop
I am using [NSThread exit] to leave the NSTimer thread.
It stops the application entirely.
How do you stop or exit NSTimer thread?
[timer invalidate];
timer = nil;
If you want to definitely stop a NSTimer you may use
[timer invalidate];
However, if you want to temporary prevent the timer to fire you may consider using
[timer setFireDate:[NSDate distantFuture]];
From Apple Documentation:
Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated. A non-repeating timer invalidates itself immediately after it fires. However, for a repeating timer, you must invalidate the timer object yourself by calling its invalidate method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes and releases the timer, either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
You should double check to make sure your timer is valid before invalidating it.
if ([timer isValid]) {
[timer invalidate];
timer = nil;
}
I am not sure what you mean by NSTimer thread, but to stop NSTimer instance you scheduled, you can call [NSTimer invalidate].

NSTimer is it thread safe?

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.

NSRunLoop freezes with NSTimer and any input

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

NSTimer: Getting firing to NOT act retroactively

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.