簡體   English   中英

iOS從通知中刪除觀察者:我可以為所有觀察者調用一次嗎? 即使沒有?

[英]iOS Remove observer from notification: Can I call this once for all observers? And even if there are none?

我在大多數視圖控制器中注冊了三個觀察者。 有些人有更多,有些人更少,但我想在父類中包含部分注冊和注銷過程。 即使沒有觀察者,調用取消注冊有什么問題嗎? 是否要求所有三位觀察員取消注冊?

- (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];
}

是的,這將刪除觀察者self所有注冊。 它在NSNotificationCenter類參考中有記錄

以下示例說明了如何someObserver注冊的所有通知取消注冊someObserver

 [[NSNotificationCenter defaultCenter] removeObserver:someObserver]; 

請注意,理論上(但據我所知,在iOS 7.0的實踐中), UIViewController可能有自己的注冊,它不希望在viewWillDisappear:刪除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:返回的每個觀察者addObserverForName:object:queue:usingBlock:是一個只有一個注冊的新對象,因此每次調用removeObserver:都保證只刪除該觀察者的一個注冊。

iOS 9 / macOS 10.11及更高版本的更新

從iOS 9和macOS 10.11開始,如果取消分配觀察者, NSNotificationCenter自動取消注冊觀察者。 它不再需要手動注銷自己在您dealloc方法(或deinit斯威夫特)如果您的部署目標是iOS的9或更高版本或者MacOS 10.11或更高版本。

對於你的第一個問題,即使沒有觀察者也可以取消注冊。 但是對於你移除觀察者的方式, [[NSNotificationCenter defaultCenter] removeObserver:someObserver]; 甚至會刪除非常推薦的超類觀察者(因為對象被卸載除了dealloc),但是在viewWillDisappear你應該使用[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];刪除觀察者[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM