2012-02-28 1 views
1

Таким образом, у меня есть объект, который имеет методы для переключения наблюдения за определенное имя уведомления, например, так:NSNotificationCenter - Наблюдение за Notification Имени с несколькими методами

- (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

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

@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

Да, [объявление ivars в '@ implementation' является законным] (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF126) с недавним компилятором. –

+0

И одна из наиболее полезных функций тоже! переменные реализации @private полезны во многих отношениях. –

+0

+1 для хорошо продуманного ответа! Я соглашусь, но это не тот метод, с которым я пошел. Я объясню в своем ответе. –

1

Таким образом, блоки и 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 не изменяется, и наоборот. Отлично!

Обновление: Большое спасибо Josh Caswell, кто предложил использовать ассоциацию объектов!

+0

Очень приятно! Мне нравится ваше решение лучше! (Я пришел в сторону маршрута уведомлений на основе блоков.) –

+0

Подождите, есть проблема с этим: переменные 'static' не будут работать в нескольких экземплярах этого класса (при условии, что каждый объект-объект возвращается каждый раз , в любом случае). Вы можете использовать несколько связанных объектов. –

+0

Отличная идея; не знал, что это было! Сделаю, и я обновлю соответствующим образом. –

 Смежные вопросы

  • Нет связанных вопросов^_^