通知被删除

时间:2018-08-25 18:20:45

标签: objective-c macos cocoa nsnotifications

我有一个模型对象和一个窗口控制器。我希望他们能够通过通知进行交流。我在App Delegate的-applicationDidFinishLaunching:方法期间创建了两者。我在加载了窗口控制器的窗口之后添加了观察者,就像这样:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    WordSetWindowController* windowController = [[WordSetWindowController alloc] initWithWindowNibName:@"WordSetWindowController"];

    model = [[WordSetModel alloc] init];

    NSWindow*   window = windowController.window;

    [[NSNotificationCenter defaultCenter] addObserver:windowController
                                             selector:@selector(handleNotification:)
                                                 name:kNotification_GeneratingPairs
                                               object:model];

    [[NSNotificationCenter defaultCenter] addObserver:windowController
                                             selector:@selector(handleNotification:)
                                                 name:kNotification_ProcessingPairs
                                               object:model];

    [[NSNotificationCenter defaultCenter] addObserver:windowController
                                             selector:@selector(handleNotification:)
                                                 name:kNotification_UpdatePairs
                                               object:model];

    [[NSNotificationCenter defaultCenter] addObserver:windowController
                                             selector:@selector(handleNotification:)
                                                 name:kNotification_Complete
                                               object:model];

    [model initiateSearch];
}

-iniateSearch方法在后台启动了一些线程来执行一些处理器密集型的计算。我希望这些线程发送通知,以便在处理过程中可以更新UI。看起来像这样:

- (void)initiateSearch;
{
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotification_GeneratingPairs
                                                        object:self];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // ... do the first part of the calculations ...

        // Notify the UI to update
        self->state = SearchState_ProcessingPairs;
        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:kNotification_ProcessingPairs
                                                                object:self];
        });

        // ... Do some more calculations ...

        // Notify the UI that we're done
        self->state = SearchState_Idle;
        dispatch_sync(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:kNotification_Complete
                                                                object:self];
        });

    });
}

第一个通知可以正常工作,但是dispatch_async()调用中发生的所有通知都不会导致调用通知处理程序。我尝试过在后台线程和UI线程上都调用-postNotificationName::(都使用dispatch_async(dispatch_get_main_queue(),...)和调用-performSelectorOnMainThread:::),但都没有任何效果。

我很好奇,我通过一个NSTimer添加了一个呼叫,该呼叫在dispatch_async()结束时的大-initiateSearch:调用之后等待了5秒,发现即使所有这些都发生在主UI上线程,它也不会触发通知处理程序。如果我在postNotification:::调用返回后立即调用dispatch_async(),则它可以正常工作。

由此得出的结论是,尽管我的代码从未调用-removeObserver:,但我还是以某种方式将观察者从通知中心中删除了。为什么会发生这种情况,我该如何避免这种情况发生,或者我该如何将呼叫移到-addObserver上,以使他们不受此影响?

1 个答案:

答案 0 :(得分:2)

怀疑您的窗口控制器被释放了。

您将其分配给WordSetWindowController* windowController,但是该引用在-applicationDidFinishLaunching:的末尾消失,并且可能与您的窗口控制器一起使用。

由于窗口本身在打开时由AppKit保留,因此最终会出现一个没有控制器的屏幕窗口。 (NSWindowNSNotificationCenter均未对其控制器/观察者保持强烈引用。)

之所以可以使用初始通知,是因为这些通知是在-applicationDidFinishLaunching:结束之前发布的,并且/或者该事件的自动释放池已耗尽。

在您的应用程序委托中为您的窗口控制器创建一个强大的引用,将窗口控制器的引用存储在那里,我怀疑所有内容都可以像宣传的那样工作。

对于我来说,一个窗口控制器也是一个表委托,发生了非常相似的事情。最初的设置和委托消息可以很好地工作,但是后来的选择事件神秘地消失了。