I'm right about what I said in my comment on drawnonward's answer.
Variables are containers. A variable is distinct from the value that's in it. Generally, when you use the name of a variable in your code, you're actually referring to the value; when you say foo(bar)
, you're not passing the bar
variable itself to the foo
function, you're passing the value that's in the bar
variable.
Local variables aren't initialized to anything unless you initialize them. So, don't ever refer to a local variable without either assigning to it or initializing it previously. Random bad things will randomly happen.
Instance variables, on the other hand, are initialized to nil
, and will continue to contain nil
until you put something else in them. This matters because all through init
, you haven't put anything in the testWindow
instance variable, so it contains nil
.
Then, by saying addObserver:… selector:… name:… object:testWindow
, you pass that default value, nil
, as the object for which you want to observe for notifications. That translates to observing for that notification for any object.
That isn't what you meant, but what you meant isn't what you wrote. What you meant is to add yourself as an observer for the test window. But you haven't created the test window yet, and you haven't put its pointer in the testWindow
variable, so what you wrote is to add yourself as an observer for any object.
Only when the notification happens do you create the window (incorrectly, at that) and assign it to the variable. This is too late for it to have any effect on your observation; the assignment does not retroactively change how you're observing, because you could only pass what was in the variable at that time (which was nil
); you could not and cannot pass the variable nor any possible future values of the variable.
So, you need to create the window and assign to the variable in init
, then add yourself as an observer for the notification.
There are two correct ways to create a window in code. This is one of them, and this is the other. Don't use plain init
to create a window, because it will have no frame rectangle.
Or, better yet, instead of doing all this in code, just use IB to make the window. You'll need to make testWindow
an outlet and start observing in awakeFromNib
.
Either way, you have a problem on the other end, too, because you release
(and thereby destroy, or at least attempt to destroy) the window in your notification method. Don't expect to continue receiving notifications for an object after you destroy it. You need to move that release
message and nil
assignment out to someplace else in your code, to a place where you're truly finished with the window and not just hiding it temporarily.
In summary:
- Create the window and assign its pointer to the
testWindow
variable in init
, before you send that addObserver:selector:name:object:
message.
- For a window that the user can show and hide, keep the window's lifetime separate from its shown/hidden state. It's OK to have a window object that's ordered out; you don't need to destroy it as soon as you order it out. Memory isn't that scarce anymore—not on the Mac, anyway. Release the window only when you are truly done with it—probably just in
dealloc
.
(Oh, and a style/maintanability matter: Don't sprinkle literal strings like @"TestNotification"
all over your code. Define a variable with that value somewhere, and use that variable everywhere you want to use the notification. Then, to change the string, you change it in exactly one place, and to rename the variable, you can use Xcode's Refactor tool.)