我在大多数视图控制器中注册了三个观察者。有些人有更多,有些人更少,但我想在父类中包含部分注册和注销过程。即使没有观察者,调用取消注册有什么问题吗?是否要求所有三位观察员取消注册?
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterBackground:)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
//Has to be unregistered always, otherwise nav controllers down the line will call this method
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
答案 0 :(得分:58)
是的,这将删除观察者为self
的所有注册。它记录在NSNotificationCenter Class Reference:
以下示例说明了如何为之前注册过的所有通知取消注册
someObserver
:[[NSNotificationCenter defaultCenter] removeObserver:someObserver];
请注意,理论上(但据我所知,在iOS 7.0的实践中),UIViewController
可能有自己的注册,不希望在viewWillDisappear:
中删除。使用addObserver:selector:name:object:
注册公共API中的任何通知都不太可能,因为这会阻止您在UIViewController
子类中注册它们,但它当然可以注册非公开通知未来的版本。
取消注册的一种安全方法是每次注册时发送一次removeObserver:name:object:
:
- (void)deregisterForKeyboardNotifications {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[center removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self deregisterForKeyboardNotifications];
}
- (void)dealloc {
[self deregisterForKeyboardNotifications];
}
另一种方法是使用addObserverForName:object:queue:usingBlock:
注册(而不是addObserver:selector:name:object:
)。这将为每个注册返回一个新的观察者对象引用。您必须将它们保存起来(如果您不想创建单个实例变量,可能在NSArray
实例变量中)。然后将每个传递给removeObserver:
以取消注册其通知。例如:
@implementation MyViewController {
NSMutableArray *observers;
}
- (void)registerForKeyboardNotifications {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *queue = [NSOperationQueue mainQueue];
__weak MyViewController *me = self;
observers = [NSMutableArray array];
[observers addObject:[center addObserverForName:UIKeyboardWillShowNotification
object:nil queue:queue usingBlock:^(NSNotification *note) {
[me keyboardWillShow:note];
}]];
[observers addObject:[center addObserverForName:UIKeyboardWillHideNotification
object:nil queue:queue usingBlock:^(NSNotification *note) {
[me keyboardWillHide:note];
}]];
[observers addObject:[center addObserverForName:UIApplicationWillResignActiveNotification
object:nil queue:queue usingBlock:^(NSNotification *note) {
[me applicationWillResignActive:note];
}]];
}
- (void)deregisterForKeyboardNotifications {
for (id observer in observers) {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
observers = nil;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self deregisterForKeyboardNotifications];
}
- (void)dealloc {
[self deregisterForKeyboardNotifications];
}
由于addObserverForName:object:queue:usingBlock:
返回的每个观察者都是一个只有一次注册的新对象,因此每次调用removeObserver:
都只能删除该观察者的一次注册。
从iOS 9和macOS 10.11开始,如果取消分配观察者,NSNotificationCenter
会自动取消注册观察者。如果您的部署目标是iOS 9或更高版本或macOS 10.11或更高版本,则不再需要在dealloc
方法(或Swift中的deinit
)中手动取消注册。
答案 1 :(得分:7)
对于你的第一个问题,即使没有观察者也可以取消注册。
但是对于你移除观察者的方式,[[NSNotificationCenter defaultCenter] removeObserver:someObserver];
甚至会删除超级观察者,这是非常不推荐的(除了dealloc因为对象已被卸载),但在viewWillDisappear
中你应该删除观察员使用[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];