objective-c - 被移除的通知
问题描述
我有一个模型对象和一个窗口控制器。我希望他们能够通过通知进行交流。我在 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()
任何通知都不会导致调用通知处理程序。我已经尝试-postNotificationName::
在后台线程和 UI 线程上调用(通过 usingdispatch_async(dispatch_get_main_queue(),...)
和 call -performSelectorOnMainThread:::
),但都没有任何效果。
好奇的是,我通过一个NSTimer
在大dispatch_async()
调用结束后等待 5 秒的调用添加了一个调用-initiateSearch:
,发现即使这一切都发生在主 UI 线程上,它也不会触发通知处理程序。如果我只是postNotification:::
在调用返回后立即dispatch_async()
调用,它可以正常工作。
由此,我得出结论,尽管我的代码从未调用 -removeObserver:,但观察者不知何故被从通知中心删除。为什么会发生这种情况,我怎样才能防止它发生,或者我可以将我的电话转移到哪里,-addObserver
以便他们不受此影响?
解决方案
怀疑您的窗口控制器正在被释放。
您将其分配给WordSetWindowController* windowController
,但该引用在 结束时消失了-applicationDidFinishLaunching:
,并且可能是您的窗口控制器与它一起消失。
由于窗口本身在打开时由 AppKit 保留,因此您最终会得到一个没有控制器的屏幕窗口。(既不NSWindow
维护NSNotificationCenter
对其控制者/观察者的强烈引用。)
初始通知有效,因为这些通知是在-applicationDidFinishLaunching:
结束之前发布的和/或该事件的自动释放池已耗尽。
在应用程序委托中创建对窗口控制器的强引用,将窗口控制器的引用存储在那里,我怀疑一切都会像宣传的那样工作。
我的一个窗口控制器也发生了非常相似的事情,它也是一个表委托;最初的设置和委托消息可以完美运行,但后来选择事件神秘地消失了。
推荐阅读
- java - Java:当我插入带有标题虚拟节点的循环双向链表时,我的虚拟节点被打乱了。为什么?
- python-3.x - Python 慢慢爬取网站
- php - 如何通过文件ID为谷歌驱动器链接生成直接下载链接
- android - gradle 错误 - com.google.common.collect.ImmutableSet.toImmutableSet()Ljava/util/stream/Collector
- scala - 如何拦截使用 Akka HTTP 发出的 HTTP 客户端请求?
- regex - 在文件中查找字符串并在 Linux 中执行部分数学运算
- ios - iOS 11.2 之前的订阅促销
- android - CountDown Timer 不会在 Android 中停止 Value ListView
- javascript - Ajax Load 在 setTimeout 中递归工作?
- unity3d - 从 Unity 访问 TrueDepth