Please don't take this badly, but... oh my god.
Your hasFocus() function is a bit wordy but I guess that's ok. I've almost
never had to use such a thing. If you did want to make such a generic
thing, it would be much better to put it as a category on NSView than to
write an external function, though. There's no real point in some of the
checks; you could rewrite it as:
- (BOOL)hasFocus
{
id responder = [[self window] firstResponder];
return self == responder || ([responder
respondsToSelector:@selector(isFieldEditor)] && [responder isFieldEditor]
&& [[responder delegate] == self]
}
As a bonus this will also correctly handle first responders that are not
NSText* objects.
Now, on to the bit that leads me to say "oh my god". One of the great
evils in most programming is polling. Polling is where you watch for a
change by continually checking the current state, rather than waiting for
a notification. An example of polling would be:
while( !MouseButtonDown() )
; // do nothing
... mouse was clicked now...
Instead of:
- (void)mouseDown: (NSEvent *)event {
...mouse was clicked now...
Polling is evil because it's extremely wasteful. On any modern operating
system you share the computer with a lot of other programs. Sitting in a
loop that doesn't do anything takes resources that these other programs
could be using to do something useful. If your OS and libraries are
designed properly then waiting for an event to arrive will require no CPU.
Your -handleTimerPulse: method is a classic example of polling. It will
check the window's first responder a hundred times a second to see if it's
changed. This is going to waste a ton of CPU power, which will in turn
make every other application on the system run slower, and greatly harm
battery life for portable users.
Much better would be to simply listen for
NSControlTextDidBeginEditingNotification. This will get triggered whenever
the user starts editing. Or better yet, find a better way to do whatever
it is you're doing in response to a field getting focus. In my many years
of working with Cocoa, I've never had to do this that I can recall. It is
of course entirely possible that you *do* need it, but without knowing
more about it, it sounds indicative of a conceptual problem or a broken
GUI.
Obviously if you have CPU-intensive work that needs to be accomplished
then you do need this sort of timer, and that's not considered polling.
(Because you're doing real work.) But you should create the timer only
when needed, and stop it when the work is complete.
--
Michael Ash
Rogue Amoeba Software