我在大多数视图控制器中注册了三个观察者.有些人有更多,有些人更少,但我想在父类中包含部分注册和注销过程.即使没有观察者,调用取消注册有什么问题吗?是否要求所有三位观察员取消注册?
- (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]; }
rob mayoff.. 59
是的,这将删除观察者所在的所有注册self
.它在NSNotificationCenter类参考中有记录:
以下示例说明了如何取消注册
someObserver
之前已注册的所有通知:[[NSNotificationCenter defaultCenter] removeObserver:someObserver];
请注意,理论上(但据我所知,在iOS 7.0的实践中),UIViewController
可能有自己的注册,它不想删除viewWillDisappear:
.它不太可能在公共API中使用注册任何通知addObserver:selector:name:object:
,因为这将阻止您在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
方法(或deinit
Swift)中手动取消注册.
对于你的第一个问题,即使没有观察者也可以取消注册.但是对于你移除观察者的方式,[[NSNotificationCenter defaultCenter] removeObserver:someObserver];
甚至会删除超级观察者,这是非常不推荐的(除了因为对象被卸载而在dealloc中),但viewWillDisappear
你应该通过使用逐个删除观察者[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
是的,这将删除观察者所在的所有注册self
.它在NSNotificationCenter类参考中有记录:
以下示例说明了如何取消注册
someObserver
之前已注册的所有通知:[[NSNotificationCenter defaultCenter] removeObserver:someObserver];
请注意,理论上(但据我所知,在iOS 7.0的实践中),UIViewController
可能有自己的注册,它不想删除viewWillDisappear:
.它不太可能在公共API中使用注册任何通知addObserver:selector:name:object:
,因为这将阻止您在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
方法(或deinit
Swift)中手动取消注册.