鉴于即使方法调用正在进行中,对象也可能被释放(link)*,对象注册并接收将在与其预期释放的线程不同的线程上传递的通知是否安全?
作为参考,文档指出
在多线程应用程序中,通知始终在发布通知的线程中传递,该线程可能与观察者注册自身的线程不同。
同样重要的是,NSNotificationCenter 不会保留对注册接收通知的对象的强引用。
这是一个可能使情况更加具体的示例:
- (id)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:SomeNotification object:nil];
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)handleNotification:(NSNotification *)notification {
// do something
}
具有此实现的对象在线程 X 上接收 SomeNotification。在 -handleNotification: 返回之前,对该对象的最后一个强引用(在我可以看到的代码中)被破坏。
-
我的想法是否正确:
A。如果 NSNotificationCenter 在调用 -handleNotification: 之前对该对象进行了强引用,那么直到 -handleNotification: 返回之后该对象才会被释放,并且
b.如果 NSNotificationCenter 在调用 -handleNotification: 之前没有对该对象进行强引用,那么该对象可能会在 -handleNotification: 返回之前被释放
它以哪种方式(a 或 b)起作用?我还没有在文档中找到这个主题,但是在多线程环境中安全地使用 NSNotificationCenter 似乎有些重要。
UPDATE:上述链接中的答案已更新,表明“ARC 围绕弱引用的调用保留和释放”。这意味着在方法调用正在进行时不应释放对象。
我总是建议,如果您看到通知在主线程以外的线程上飞来飞去,并且您看到在后台发生释放,则您的线程可能太复杂了。 ObjC 不是一种线程友好的语言。大多数线程工作应该以队列上的短期块的形式存在。他们可以轻松地将通知发布回主线程,但不应经常使用通知。
也就是说,当今管理多线程通知的最佳方法是addObserverForName:object:queue:usingBlock:
。这使您可以更好地控制生命周期。该模式应该看起来像这样:
__weak id weakself = self;
id notificationObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:...
object:...
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note){
id strongself = weakself;
if (strongself) {
[strongself handleNotification:note];
}
}];
注意weakself/strongself 的使用。我们使用weakself 来避免retain 循环。当我们回来时,我们首先采取强有力的参考。如果我们仍然存在,那么我们将被锁定在该块的其余部分(因此我们无法释放handleNotification:
)。如果我们不存在,则通知将被丢弃。 (请注意,弱引用在调用之前实际上已归零dealloc
. See objc_loadWeak。) 我在用着mainQueue
在这里,但您当然可以使用另一个队列。
在“过去”(10.6 之前),我通过控制对象生命周期来解决这个问题。基本上,我的设计是使短期对象不会侦听可能来自其他线程的通知。这比听起来容易得多,因为在 10.6 之前的代码中,线程可以保持非常罕见(在我看来,仍然应该保持在较低水平)。NSNotificationCenter
是为低线程世界而设计的。
另请注意,与-[NSNotificationCenter addObserver:selector:name:object:]
, -[NSNotificationCenter addObserverForName:object:queue:usingBlock:]
返回一个充当观察者的不透明对象。您必须跟踪该对象,以便稍后可以删除观察者。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)