In my NSApp delegate I add an observer of an object that is an NSWindow subclass that gets initiated in the delegate itself and that posts a notification once the window gets clicked. The selector is also in the delegate. From that same delegate class I initiate another object which when initiated adds itself as an observer for another window of the same NSWindow subclass of above and the selector is in this newly initiated class too. Both notifications get posted but the problem is that they get posted in both classes… Is this normal? I was hoping that it only got posted once.
@implementation AppController
- (id)init
{
if (self = [super init])
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(toggleTestWindow:) name: @"TestNotification" object: testWindow];
return self;
}
- (void)toggleTestWindow: (NSNotification *)aNotification
{
if (!testWindow) {
testWindow = [[MyWindow alloc] init];
[mainWindow addChildWindow: testWindow ordered: NSWindowAbove];
} else {
[mainWindow removeChildWindow: testWindow];
[testWindow orderOut: self];
[testWindow release];
testWindow = nil;
}
}
@end
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 thebarvariable itself to thefoofunction, you’re passing the value that’s in thebarvariable.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 containniluntil you put something else in them. This matters because all throughinit, you haven’t put anything in thetestWindowinstance variable, so it containsnil.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
testWindowvariable, 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
initto 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
testWindowan outlet and start observing inawakeFromNib.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 thatreleasemessage andnilassignment 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:
testWindowvariable ininit, before you send thataddObserver:selector:name:object:message.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.)