开发者

Not receiving NSWindowWillCloseNotifications

In the application I am creating, I have a welcome window with a list of recent documents (similar in functionality to the new Xcode 4's welcome window). I am registering both the application's delegate and a view controller in the welcome window for posted NSWindowWillCloseNotification. Unfortunately, only the applications delegate is ever getting notified of this event.

I've tried the following, all with the same behavior (the window controller is not notified):

  • Removing the AppDelegate's notification registration code, hoping that somehow it was 'consuming' the notification.
  • Changing the method on the view controller to -(void)windowIsClosing: such that it isn't the same name as the app delegate (quite the long shot, but I had to try)
  • Moving the addObserver:... call in the ViewController to else where in the code (so its not invoked during the initializer, if somehow that mattered).
  • I do de-register my view controller from the notification center during its dealloc method, but I've ensured that the dealloc method is getting called after the window is closed not during the closing.

I also tried for listening to other events, such as NSWindowWillMoveNotification in both the delegate and the controller, and once again the delegate gets notified but not the view controller. My view controller is not part of the first responder chain, but that shouldn't matter since I'm registering for a notification not looking to handle nil-targetted actions.

Therefore, why is my controller not being notified of the window closing events but my app delegate is?

The relevant code is as follows.... App Delegate:

@interface AppDelegate : NSObject <NSApplicationDelegate> {
}
@end

@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(windowClosing:) 
                                                 name:NSWindowWillCloseNotification 
                                               object:nil];
    // other initialization stuff
    [self showWelcomeWindow];
}

- (void)windowClosing:(NSNotification*)aNotification {
    // this method gets called when any window is closi开发者_StackOverflow中文版ng
}
@end

Controller:

@interface ViewController : NSObject {
}
@end

@implementation ViewController
- (id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(windowClosing:)
                                                     name:NSWindowWillCloseNotification
                                                   object:nil];
    }
    return self;
}

- (void)windowClosing:(NSNotification*)aNotification {
    // this method does not called when window is closing
}
@end


Answering my own question for posterity now that I've figured it out.

As stated in the NSNotificationCenter documentation:

Be sure to invoke removeObserver: or removeObserver:name:object: before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated.

The ViewController object was listening to notifications for windows that are closing (NSWindowWillCloseNotifications) and to one of my data model object's notifications.Therefore when I was setting a different model object on the controller I was de-registering the ViewController from listening to the model object that was being replaced.

Unfortunately, I chose to use the removeObserver: method (which also removed the object from being notified of window closing events) rather than the more specific removeObserver:name:object: to remove my controller from only a subset of the notifications that the object had registered for. Looking back on the code, the removeObserver was written before the controller object had any need to be notified of events originating from anything other than the model.

The moral of the story is to have the mental discipline to only use [[NSNotificationCenter defaultCenter] removeObserver:self] during the object's dealloc call and to otherwise de-register from very specific events (since you cannot know down the road what other event notifications the object will be registered for as well).


If you want to watch for recently-used documents you can subclass NSDocumentController and implement -noteNewRecentDocumentURL:; Cocoa will then let you know when it updates the same list that goes into File > Open Recent.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜