哪种方法更好地删除通知观察者?

16

我通常像下面的示例一样使用 NSNotification:

在 viewDidLoad 中:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(foo:) name:kName1 object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bar:) name:kName2 object:nil];

在 viewDidUnload 和 dealloc 方法中:

[[NSNotificationCenter defaultCenter] removeObserver:self];

但我的朋友告诉我不要使用 [[NSNotificationCenter defaultCenter] removeObserver:self];,因为它会移除包括超类在内的所有观察者。他建议我使用以下代码逐个地移除观察者。

[[NSNotificationCenter defaultCenter] removeObserver:self name:kName1 object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kName2 object:nil];

我已经检查了ASIHttpRequest库的代码(https://github.com/pokeb/asi-http-request), 它遵循了我的朋友的建议。

我想知道我的朋友是不是正确的?在我看来,由于当前实例将被卸载或释放,所以超类的通知也是无用的。还有没有任何系统UIViewController子类使用通知?


它是什么意思将会移除“超类”的观察者?观察者是一个对象实例而不是一个类。如果它将要被释放,它必须从所有通知中注销自己,即使它们是在超类的代码中注册的。 - MrTJ
@MrTJ 我的意思是在父类方法中添加的通知观察者。也许,当子类的 viewDidUnload 方法被调用时,该类实例的父类也需要观察一些通知。 - tangqiaoboy
可能是,可能是。如果你想在viewDidUnload中注销,则出于安全考虑,我建议使用第二种方法(按观察者注销)。 - MrTJ
4个回答

12

您的朋友是完全正确的。但是,如果您在dealloc中删除所有通知观察,那也没关系。
您提到了viewDidUnload,在这种情况下完全不同,因为卸载的对象将保持活动状态,您不知道超类的通知观察何时会再次添加。如果它们在viewDidLoad中添加,则不会有问题。如果它们在init方法中添加,则您将失去一些重要的通知观察。

从一开始就删除特定名称的观察是一个好习惯,应该这么做。


谢谢。所以我们可以在dealloc方法中使用[[NSNotificationCenter defaultCenter] removeObserver:self];,但不能在viewDidUnload方法中使用,对吗? - tangqiaoboy
是的,removeObserver:不应该在dealloc之外使用。但我喜欢自己逐个删除每个观察,所以我根本不使用removeObserver:。我为所有通知使用特定的方法removeObserver:name:object:。我喜欢保持我的代码非常具体。 - Matthias Bauch

8

当您想删除所有通知时,使用以下命令:

[[NSNotificationCenter defaultCenter] removeObserver:self];

如果您想删除特定的通知,可以使用以下方法:
[[NSNotificationCenter defaultCenter] removeObserver:self name:kName1 object:nil];

当您不再需要任何通知时,第一种方法很简单。

1

由于对象即将离开,因此可以在dealloc方法中安全地使用[[NSNotificationCenter defaultCenter] removeObserver:self];

ViewDidUnload方法中,最好逐个删除每个观察者,因为控制器的引用仍然存在(并且您相应的viewDidLoad应该重新添加它们所有)。


0

我一直使用第一种方式,从来没有考虑过它是否正确。如果dealloc方法被调用,那么对象(包括super)都将被释放。你绝对不希望NSNotification发送到一个已释放的实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接