0

У меня есть класс Poster, который отправляет уведомления через NSNotificationCenter. У меня есть два разных наблюдателя: ObserverSuperclass и ObserverSubclass. ObserverSuperclass - это суперкласс ObserverSubclass. Я хотел бы, чтобы каждый класс реагировал по-разному на уведомление.Блокировка NSNotificationCenter с подклассами?

Согласно NSHipster, я должен использовать современный блок-интерфейс api: addObserverForName:object:queue:usingBlock:.

В способе инициализации ObserverSubclass мне нужно удалить суперкласс в качестве наблюдателя. Поскольку я использую основанный на блоках API, мне нужно ссылаться на возвращаемое значение addObserverForName:object:queue:usingBlock: - «непрозрачный объект для работы в качестве наблюдателя». Поэтому я пишу следующий код:

В ObserverSuperclass.h

@property (nonatomic, strong) id observer;

В ObserverSuperclass.m

self.observer = [NSNotificationCenter defaultCenter] addObserverForName:@"Help!" object:nil queue:nil usingBlock:^{old block}];

В ObserverSubclass.m

[[NSNotificationCenter defaultCenter] removeObserver:self.observer name:@"Help!" object:nil];

self.observer = [NSNotificationCenter defaultCenter] addObserverForName:@"Help!" object:nil queue:nil usingBlock:^{new block}];

Действительно ли это лучший способ сделать это? Я не уверен, что имеет смысл использовать основанный на блоках API.

+1

Вы можете реализовать метод, который возвращает блок обработчика. Затем вы можете просто переопределить этот метод в подклассе или просто использовать API на основе селектора – Paulw11

+0

Зачем вам нужно удалить суперкласс в качестве наблюдателя? Разве вы не хотите, чтобы этот блок выполнялся вообще? – Roberto

ответ

2

Это случай, когда, на мой взгляд, вы должны использовать традиционный @selector обратные вызовы. Ваш суперкласс может зарегистрировать наблюдение и реализовать поведение по умолчанию. Подкласс тогда нуждается только в переопределении вызываемого back @selector.

Метод, который должен осуществить это:

- (void)addObserver:(id)notificationObserver 
     selector:(SEL)notificationSelector 
      name:(NSString *)notificationName 
     object:(id)notificationSender 

Например, в суперкласса:

- (instancetype) init 
{ ... 
    [[NSNotificationCenter defaultCenter] 
      addObserver:self 
       selector:@selector(oberserveThis:) 
        name:@"someEventName" 
       object:nil]; 
} 

- (void)observeThis:(NSNotification*)notification 
{ 
    // ... Do something here ... 
} 

В подклассе:

- (void)observeThis:(NSNotification*)notification 
{ 
    // ... Do something else here ... 
} 

Если вам нужен код наблюдатель для выполнения в конкретной очереди вы всегда можете вызвать диспетчер в селектор наблюдения. Я думаю, что для вашего случая использования он делает гораздо более чистый код, чем использование блочного подхода.

+0

Это тот вывод, к которому я пришел. Я бы использовал только API на основе блоков, если бы знал, что не буду подклассифицироваться. – rizzes

0

Ваш код выглядит хорошо.

Логика, которую вы наметили, навязывает идею, что вам нужен только один наблюдатель, как суперкласс, так и подкласс. Наблюдатель вашего подкласса удаляет и заменяет наблюдателя суперкласса.

Это также верно, если они оба соблюдают одно и то же имя уведомления. В этом случае вы должны добавить новую переменную экземпляра self.newObserver в подкласс и добавить наблюдателя к этому свойству. Тогда оба блока будут вызваны, когда «Справка!» уведомление отправлено.

Что вы делаете, зависит от того, что вы пытаетесь выполнить.

Вам нужно удалить наблюдателя, когда он вам больше не нужен, или вы рискуете сбой, когда объекты, с которыми работает блок наблюдателя, будут освобождены из-под него. (Это менее вероятно с блочными наблюдателями, чем с наблюдателями на основе селектора, поскольку центр уведомлений автоматически сохраняет блок, и даже если объект, который добавляет наблюдателя, будет освобожден, блок наблюдателя все равно будет работать. С наблюдателем на основе выбора вы будете Обязательно помните, чтобы удалить своего наблюдателя в методе dealloc или вы потерпите крах после того, как ваш объект будет освобожден, если тип уведомления, который вы наблюдаете, снова отправляется.)

+0

Эта система становится немного неуклюжей, когда высота родительско-дочернего дерева больше 2. например. 3-й класс (который является подклассом 1 и 2) будет иметь self.observer, self.newObserver, self.newNewObserver. Вместо того, чтобы хранить их как отдельные свойства, используйте массив? – rizzes

+0

Это становится особенно грязным, когда классы прослушивания имеют несколько наблюдателей. Должен ли я иметь несколько массивов (или наборов self.observer [N])? – rizzes

+0

Несомненно, массив будет в порядке. Сделать базовый класс иметь изменяемый массив объектов-наблюдателей, который он создает во время init. Каждый подкласс, которому нужен собственный наблюдатель, создаст нового наблюдателя и добавит его в массив. Метод dealloc базового класса может позаботиться о том, чтобы удалить все из них. –

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