How do I replace this NSTimer with a CADisplayLink? - objective-c

I realize that a CADisplayLink would be better suited for the nature of my current project, however, i can't quite figure out how to implement a CADisplayLink and replace my NSTimer.
below is the code for my NSTimer
Movement = [NSTimer scheduledTimerWithTimeInterval:0.002 target:self selector:#selector(BarMoving) userInfo:nil repeats:YES];
how can I create a CADisplayLink that will perform the same function but more efficiently?

Create the thing:
_displayLink = [CADisplayLink displayLinkWithTarget:self
selector:#selector(BarMoving)];
Start it running:
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
... that'll cause your display link to issue calls to BarMoving on the main run loop (which is the one associated with the main thread and therefore the main queue) whenever that run loop is in the default mode. So things like when the user has their finger down scrolling a scroll view will pause your timer. NSTimer has the same default behaviour.

Related

Concurrent processing on main queue during UITableView scroll

I have a stopwatch screen in my app.
There is a main label indicating passing time every 100 milliseconds (updates constantly).
Just below that label, in the same ViewController I have a UITableView.
Whenever I'm scrolling the UITableView, the stopwatch labels stops updating.
I've tried using Grand Central Dispatch as follows, but it doesn't work and I didn't expect it would, since it's still two operations running on the same queue.
dispatch_async(dispatch_get_main_queue(),^{
MyTimerObject *t = (MyTimerObject*)notification.object;
lblMainTimer.text = t.MainTimerStringValue;});
So how should I approach this problem?
This all happens within the receiveNotification method of NSNotification, which make me wonder if it's not NSNotification that locks up during the table scroll event and not the label update...
Is your stopwatch updating with NSTimer or CADisplayLink? The issue associated with failure to update while scrolling is generally an incorrect choice of run loop modes.
For example, this will pause while tableview is scrolling.
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:#selector(handleTimer:) userInfo:nil repeats:TRUE];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Whereas this will not:
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
Bottom line, don't use NSDefaultRunLoopMode, but rather use NSRunLoopCommonModes, and you may find it continues to run even when scrolling the table view.

NStimer fire first and then on schedule

Is it possible to make a NStimer that fires first when it is initialized and then afterwards on a 0.01 seconds schedule? I have this code..
self.displayTimerTotalTime = [NSTimer timerWithTimeInterval:0.01
target:self
selector:#selector(timerFiredTotalTime:)
userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.displayTimerTotalTime forMode:NSRunLoopCommonModes];
Problem is that the user can stop the timer multiple times and run it again, but this creates a 0.01 delay every time that can cause problems for the user experience. It is not good enough to check for the delay later and remove it.
You can call the -fire method to fire the timer at any time. Just add this after the above code:
[self.displayTimerTotalTime fire];
You could always call the selector yourself:
[self timerFiredTotalTime:self.displayTimerTotalTime];

Does NSTimer run across entire app?

If I start an NSTimer like this:
#property (strong) NSTimer * messageTimer;
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
Does it continue to run when I switch to different view controllers?
Until I cancel it with:
[messageTimer invalidate]; self. messageTimer = nil;
Yes.
Okay, now here is an extended description. NSTimer registers itself on nearest NSRunLoop, that is, current dispatch loop (they may nest). This loop asks various sources for events and calls corresponding callbacks.
When it is time for NSTimer to fire, it returns YES to NSRunLoop and that runs passed callback. There is no such thing as "other current view controller". It is all about first responder and view hierarchy, neither doesn't have any effect on run loops.

loop a sound at set intervals

I'm relativly new to this so please bear with me.
I need to know how to loop a sound (or any object for that matter) at a definable interval.
Something simple like, touch a button and a small sound file plays every x seconds until you touch another button or touch the same button again.
NSTimer is what you're looking for to perform an action at specific time intervals.
Creating a simple timer to perform some action every 5 seconds would look something like this:
//This will start a repeating timer that will fire every 5 seconds
-(IBAction)startTimer {
self.timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(someAction:)
userInfo:nil
repeats:YES];
}
//The method the timer will call when fired
-(void)someAction:(NSTimer *)aTimer {
//Do stuff here
}
-(IBAction)stopTimer {
[self.timer invalidate];
}
As far as playing sounds go, iOS provides a lot of options. Fortunately Apple has provided plenty of good documentation on the different options available to you, how to choose the right one, and implement it.

NSTimer with a menu bar app

I'm working on a simple timer app, and I've created a NSStatusItem with a menu and I have some NSTextField labels that updates the timer labels (http://cld.ly/e81dqm) but when I click on the status item the NSTimer stops (and stops updating the labels)..... how can I get around this problem?
EDIT: here's the code that starts the timer:
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerDidUpdate:) userInfo:nil repeats:YES];
You should add timer into MainRunLoop as given below:
NSRunLoop * rl = [NSRunLoop mainRunLoop];
[rl addTimer:timer forMode:NSRunLoopCommonModes];
I'm guessing the timer resumes as soon as you stop interacting with the NSStatusItem? (After the menu's dismissed & mouse button released).
The user interaction puts the main run loop into a mode where it doesn't update timers, so if your label has to continually update, you'll probably need to move the NSTimer and the label drawing to a separate process or another thread.