NSNotificationCenter - Наблюдение за именем уведомления с несколькими методами - PullRequest
1 голос
/ 28 февраля 2012

Итак, у меня есть объект, у которого есть методы для переключения наблюдения за определенным именем уведомления, например:

- (void)startWatchingForA
{
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleA:)
                                                 name: SomeNotificationName
                                               object: nil];
}

- (void)stopWatchingForA
{
    [[NSNotificationCenter defaultCenter] removeObserver: self
                                                    name: SomeNotificationName
                                                  object: nil];
}

, который работает нормально.Однако у меня есть другой метод, handleB:, который должен отвечать на то же уведомление.

- (void)startWatchingForB
{
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleB:)
                                                 name: SomeNotificationName
                                               object: nil];
}

- (void)stopWatchingForB
{
    [[NSNotificationCenter defaultCenter] removeObserver: self
                                                    name: SomeNotificationName
                                                  object: nil];
}

Проблема заключается в том, что при вызове stopWatchingA или stopWatchingB объект перестанет наблюдатьдля обоих.Есть ли какой-нибудь способ удалить один экземпляр наблюдения, но не другой?

В идеале, когда я звоню stopWatchingForA, я хочу, чтобы handleA: не вызывался, полностью независимо от B.

Ответы [ 2 ]

2 голосов
/ 28 февраля 2012

Как насчет небольшой редизайн?Только один метод для получения уведомления и два флага, чтобы указать, что вы хотите с ним сделать.

@implementation ThisObject
{
   BOOL isWatchingForA;
   BOOL isWatchingForB;
}

- (void) registerForNotifications {

    [[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(handleNotification:)
                                             name: SomeNotificationName
                                           object: nil];
}

- (void) deregisterForNotifications {
    if( !isWatchingA && !isWatchingB ){
        [[NSNotificationCenter defaultCenter] removeObserver: self
                                                name: SomeNotificationName
                                              object: nil];
    }
}


- (void) startWatchingForA {
    isWatchingForA = YES;
}
- (void) stopWatchingForA {
    isWatchingForA = NO;
}

- (void) startWatchingForB {
    isWatchingForB = YES;
}
- (void) stopWatchingForB {
    isWatchingForB = NO;
}

- (void) handleNotification: (NSNotification *)note {

    if( isWatchingForA ){
        [self handleA:note];
    }
    if( isWatchingB ){
        [self handleB:note];
    }
}

//...

@end
1 голос
/ 28 февраля 2012

Так что блоки и mikeash , опять же, закончили тем, что спасли мой день!

Одна вещь, которую я пропустил в своем первоначальном вопросе, состояла в том, что я хотел бы, чтобы эта парадигма была безопасна для категории, что означало отсутствие иваров или свойств в качестве флагов. Вот что я в итоге сделал:

#import <objc/runtime.h>

static void *AHandlerKey;
static void *BHandlerKey;

- (void)startWatchingForA
{
    // initialize `void (^aBlock)(NSNotification *)` block
    id AHandler = [[NSNotificationCenter defaultCenter] addObserverForName: SomeNotificationName
                                                                    object: nil
                                                                     queue: nil
                                                                usingBlock: aBlock];

    objc_setAssociatedObject(self, AHandlerKey, AHandler, OBC_ASSOCIATION_RETAIN);
}

- (void)stopWatchingForA
{
    id AHandler = objc_getAssociatedObject(self, AHandlerKey);
    [[NSNotificationCenter defaultCenter] removeObserver: AHandler
                                                    name: SomeNotificationName
                                                  object: nil];
}

- (void)startWatchingForB
{
    // initialize `void (^bBlock)(NSNotification *)` block
    id BHandler = [[NSNotificationCenter defaultCenter] addObserverForName: SomeNotificationName
                                                                    object: nil
                                                                     queue: nil
                                                                usingBlock: bBlock];

    objc_setAssociatedObject(self, BHandlerKey, BHandler, OBC_ASSOCIATION_RETAIN);
}

- (void)stopWatchingForB
{
    id BHandler = objc_getAssociatedObject(self, BHandlerKey);
    [[NSNotificationCenter defaultCenter] removeObserver: BHandler
                                                    name: SomeNotificationName
                                                  object: nil];
}

Таким образом, AHandler получает уведомления, тогда как aBlock выполняется, и BHandler / bBlock также. Когда я удаляю AHandler в качестве наблюдателя, BHandler не затрагивается, и наоборот. Отлично!

Обновление: Большое спасибо Джошу Касвеллу, который предложил использовать ассоциацию объектов!

...