CHAPTER ONE: We're not going to be writing one of those BORING apps like
all the OTHER books make you do! No sir! In this book we'll be showing
you how to write a horoscope calculator, a mood ring simulator, an
EZ-Bake Oven temperature regulator, a Cabbage Patch Kids cards catalog,
and a Jim Morrison random lyrics generator! Oh my, isn't that
delightfully impertinent? Yeah, I thought so too!
CHAPTER TWO: "Why Objective-C?" Yes, that's a very good question, isn't
it? Okay, let's ponder that one. You want to make an informed
decision, don't you? Let's think about the pros and cons. Pro: You
have to use it if you're going to write Cocoa programs. Case closed!
Don't worry, you can learn the entire language in 12 picoseconds. Heck,
it only took Brad Cox 14 femtoseconds to create the entire thing, and
but a few more to sell out to Apple and forget the whole sordid episode!
Okay, let's move on.
CHAPTER THREE: Blah blah blah Project Builder blah blah blah Interface
Builder blah blah? blah! "outlets" blah blah BLAH, blah BLAH make the
connections, blah blah NIBs blah: blah; bLaH now write some code blah
blah blah look at all the progress you're making! blah blah drag it from
the control palette build run GOOD CHRIST, will you LOOK at that? You
just wrote your first Cocoa app! And it's great! INCREDIBLY great! My
GOD, that app -- the one that YOU wrote, I should point out, it was very
definitely NOT written by ME, the book author, no no no YOU, YOU are the
one who wrote it ALL -- that app is so STUNNING, I swear to GOD I'm
about to SHIT MY PANTS. I think you should MARCH RIGHT INTO STEVE JOBS'
OFFICE right this VERY SECOND and plop yourself down on his DESK and
REFUSE to LEAVE until he gives you a JOB with a SIX-FIGURE SALARY,
that's what kind of programmer YOU are, pal.
CHAPTER FOUR: Now let's add some new features, you studly programmer
you. Okay, add this one line of code. Oh my god! It Just Works! Look
at all that functionality you got -- FOR FREE! Didn't I TELL you Cocoa
was great? Didn't I TELL you Objective-C was great? DIDN'T I?? Now
add one more line of code -- OH MY GOD YOUR APP IS NOW MORE
FULL-FEATURED THAN MICROSOFT WORD! YOU COULD SELL THIS APP FOR ONE
THOUSAND DOLLARS TO ALL COMERS! THEY WON'T BE ABLE TO PULL BITS OUT OF
THE BIT BUCKET FAST ENOUGH TO MAKE NEW COPIES OF YOUR PROGRAM, THAT'S
HOW FAST IT WILL SELL!!!!!!1!!!!!!!!1!!!!!!!111!!
CHAPTERS FIVE THROUGH TWELVE: Well, there's a few little details to be
ironed out, I guess. This will require two hectobillion square
brackets, and will involve Cocoa methods that have names that are no
fewer than twelve humptosquillion characters long. You like typing,
right?
Bitter? Who, ME? No, not at all.
So, it all started with a little bathroom reading. I keep "Cocoa
Recipes for MacOSX" on top of the toilet tank. It's the most recent
Cocoa book I've bought, and by the time it was released I was pretty
sick of them, so I'm sure I've read less than five percent of it. That
book will probably be the last. I just happened to flip it open to a
chapter where the author is telling you how to enable your text input
controls to receive dropped text. I was very surprised that you have to
do anything at *all* to make that work. Isn't Cocoa all about the cool
functionality you get "for free?" Even lowly BeOS gives you that one
"for free." The author says that by default, text controls that already
have the input focus will accept dropped text, otherwise they won't. I
tested against the Cocoa text control I wrote just a few days ago, and
sure enough, he's right.
So the author shows how to make that work, and basically, it's a big
hack. You start implementing the NSDragTarget protocol, but after only
one method you force your control to steal the input focus, and that
forces the current window's NSTextField to take over, and since it
implements all NSDragTarget methods itself, it finishes up the
operation. Bleargh. What if the user didn't *want* that control to get
the input focus?
To save on memory and CPU cycles, each Cocoa window has one and ONLY one
"real" text input field. All controls in a window that allow the user
to type into them share this one text input field, round-robin. I guess
the thinking is that only one control can have the input focus at a
time, so there's no need for more than one "real" text input field. I
suppose it might be a good idea if you had a window with thousands of
controls on it, but that's rarely the case, and it unnecessarily
complicates things. There's an NSWindow method that returns its text
input control. Another you can override to apply a custom input control
for a window. If you want to get text out of a control, you do it one
way if it has the input focus, another way if it doesn't. You can get a
text selection from a control that has the input focus, but you cannot
if it doesn't. The lone input control is constantly being loaded and
unloaded with data as it shuffles among controls, which very well might
make it *less* CPU-efficient than if each control had its own text input
facilities. The lone input control may not have the same font and point
size as all its client controls do, so if that bugs you, you have to
write code to update its font on every switch (yes, I got bit by that
one). It complicates undo/redo handling in ways I'm not even going to
get into. This was a bad idea all around, if you ask me.
While I was fixing that, I ran across a method that might solve a
long-standing bug of mine. I can't get input focus to work like I want
it to. Here's how it works on BeOS: by default, the first control added
to a window will have input focus when the window is first displayed.
Pressing TAB will take you to the second control added, then the third,
and so on, until you're back to the first. By default, that's the way
it works on Cocoa, too. So far so good. But say you don't want the
first control to be the one with the input focus when the window is
first displayed. On BeOS, you call BView::MakeFocus() on the view you
want to be first before the window is displayed. Done. I tried calling
the comparable focus function on MacOSX, NSWindow.makeFirstResponder,
but it doesn't work.
Today I discovered there's a *different* function you're supposed to use
for this situation on Cocoa, if the window is not yet visible:
NSWindow.setInitialFirstResponder. I don't see why they need two of
them, but okay, fine. Did that. Works! Yay!
BUT. When you do that, it screws up the "key view loop," as they call
it. That's the circle of views that get input focus, one after another,
as you press tab. So, you can set some non-default view to be the first
responder, but if you do, you've rendered the tab key useless.
DRAT. I've been fighting that one all day. First thing I tried: Don't
use setInitialFirstResponder, wait until the window is onscreen and then
use the more traditional makeFirstResponder. Doesn't work for some
types of views for some reason. Okay, second thing: save the current
key view loop, call setInitialFirstResponder, then restore the old key
view loop that Cocoa wrecked. Doesn't work. Apparently the key view
loop doesn't exist before the window is first displayed.
WOW-EE, YOU SURE DO GET A WHOLE LOT OF FUNCTIONALITY "FOR FREE" WITH
COCOA, DON'T YOU?? GOSH! I THINK I'M GOING TO SIT RIGHT DOWN AND WRITE
AVIE TEVANIAN A NICE THANK-YOU NOTE!
The "normal" way to solve this is to wire up your key view loop in
Interface Builder, and not rely on the defaults. But even if I was
using Interface Builder, isn't that kinda lame? In all my years of BeOS
coding I've only had to screw with the default tab ordering once or
twice. Why can't we have this "for free?"
I sure hope Cocoa doesn't turn into smoke and mirrors, once you know it
real well.