iOS从通知中删除观察者:我可以为所有观察者调用一次吗?即使没有?

 李小白无悔 发布于 2023-01-30 17:49

我在大多数视图控制器中注册了三个观察者.有些人有更多,有些人更少,但我想在父类中包含部分注册和注销过程.即使没有观察者,调用取消注册有什么问题吗?是否要求所有三位观察员取消注册?

- (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及更高版本的更新

从iOS 9和macOS 10.11开始,NSNotificationCenter如果取消分配观察者,则自动取消注册观察者.如果您的部署目标是iOS 9或更高版本或macOS 10.11或更高版本,则不再需要在您的dealloc方法(或deinitSwift)中手动取消注册.

2 个回答
  • 对于你的第一个问题,即使没有观察者也可以取消注册.但是对于你移除观察者的方式,[[NSNotificationCenter defaultCenter] removeObserver:someObserver];甚至会删除超级观察者,这是非常不推荐的(除了因为对象被卸载而在dealloc中),但viewWillDisappear你应该通过使用逐个删除观察者[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];

    2023-01-30 17:52 回答
  • 是的,这将删除观察者所在的所有注册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及更高版本的更新

    从iOS 9和macOS 10.11开始,NSNotificationCenter如果取消分配观察者,则自动取消注册观察者.如果您的部署目标是iOS 9或更高版本或macOS 10.11或更高版本,则不再需要在您的dealloc方法(或deinitSwift)中手动取消注册.

    2023-01-30 17:52 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有