Когда использовать NSNotificationCenter

Я хочу иметь несколько наблюдателей за несколькими событиями одного объекта (отношения 1-к-N).

Механизм для выполнения этой задачи предоставляется NSNotificationCenter. Механизм выглядит довольно излишним при использовании для моей проблемы.

Как бы я сделал это вручную без использования NSNotificationCenter:

- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;

для добавления и удаления наблюдателей из моего объекта.

- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
    for (id delegate in delegates) {
        NSObject *data = [eventData copy];
        [delegate someEventFired:data];
    }
}

Этот механизм прямолинеен и прост в реализации, при этом объекты не должны совместно использовать дополнительные строки.

  • Существует ли официальный шаблон для делегатов 1-to-N (например, событий C#) в среде iOS помимо NSNotificationCenter?
  • Когда следует использовать NSNotificationCenter, а когда нет?
  • Когда следует использовать реализацию, подобную той, которую я предлагаю здесь, а когда нет?

person Etan    schedule 31.05.2012    source источник
comment
Я редко или когда-либо использовал NSNotificationCenter, но использовал тот же метод, который вы описываете. Я использовал это во многих приложениях iOS (я бы сказал, более 50 приложений) в течение многих лет, и пока не видел никаких проблем с этим. Возможная ошибка может заключаться в том, что вам нужно время от времени удалять наблюдателей, иначе они могут не быть освобождены, когда ожидается, потому что они остаются у хранителя делегатов.   -  person Jonny    schedule 05.12.2014
comment
Я думаю, что хотя NSNotificationCenter — это не тот подход, который мы знаем из C#, нам все же следует сосредоточиться на использовании шаблонов проектирования для конкретной платформы, для которой мы работаем. Тем не менее, я использовал NSNotificationCenter сейчас в нескольких приложениях (хотя и не так много, как вы), и я не думаю, что код от этого стал хуже.   -  person Etan    schedule 05.12.2014


Ответы (7)


По соглашению делегаты, вероятно, следует использовать только для отношений 1:1. Если вам действительно нужны отношения 1:N для этого типа функциональности, у вас есть два варианта:

  1. Как вы упомянули, NSNotificationCenter< /а>.
  2. Наблюдение за ключом и значением (также известное как КВО).

KVO подходит, если вас интересует только изменение конкретного свойства объекта. В противном случае вам следует просто рассмотреть возможность использования NSNotificationCenter. Вы даже можете получать уведомления только тогда, когда конкретный объект публикует это уведомление, передав этот объект в метод addObserver:selector:name:object:.

Apple использует NSNotification в аналогичных сценариях (например, уведомления, определенные для UITextField, включая UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification и UITextFieldTextDidEndEditingNotification).

person Sebastian Celis    schedule 31.05.2012
comment
Скажите, правильно ли я его использую? stackoverflow.com/questions/42111829/ - person Leandro De Mello Fagundes; 10.02.2017

использование уведомлений является широковещательным: 1 отправитель просто отправляет информацию, а кто когда-либо настроился, получает ее. Мелко похоже на радиостанцию, обратного канала нет (на время забудем о телефонах)

делегирование — это нечто другое. Объект, который просит делегата что-то сделать, обычно нуждается в результате этого запроса, поэтому делегирование представляет собой связь один к одному, которая всегда инициируется объектом, а не делегатом (в то время как объект может иметь методы, которые может вызываться для информирования объекта о необходимости инициировать связь, т.е. [tableView reloadData]).

Поэтому, если отправителю нужно вернуть данные, это делегирование. Если отправителя ничего не волнует после трансляции, используйте уведомления.

Если вы столкнулись с ситуацией, что вам нужно делегирование, но несколько объектов должны реализовывать протокол. у вас должен быть 1 делегат, который содержит ссылки на другие объекты и вызывает методы от имени отправителя — или вы можете использовать блоки.

person vikingosegundo    schedule 31.05.2012
comment
Сегодня у меня был бы только один объект, которым пользуются все венчурные капиталисты и который информирует их. - person vikingosegundo; 13.05.2016

NSNotificationCenter не является излишним для того, что вы предлагаете, это точно правильное решение. Это предотвращает необходимость того, чтобы наблюдаемый объект знал или заботился о своих наблюдателях, делая ваш код более слабо связанным и чистым.

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

person jrturton    schedule 31.05.2012

Предлагаемое вами решение не проще, чем использование NSNotificationCenter, и не является потокобезопасным.

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

Ваше решение также требует, чтобы вы поддерживали массив делегатов в своем классе. С NotificationCenter вы можете просто использовать центр по умолчанию, и вам не нужно реализовывать методы добавления/удаления в вашем классе. Вместо этого экземпляры могут зарегистрироваться для получения уведомлений по своему усмотрению (селектор/блок, очередь, источник). Вашему исходному классу не нужно беспокоиться об этих деталях. Ему нужно только зарегистрироваться как источник уведомлений указанного типа. Использование блоков для обработки уведомлений действительно удобно.

Альтернативой центру уведомлений является использование Key-Value-Observing, если это соответствует потребностям вашего варианта использования.

В конечном счете, механизм, который вы решите использовать, зависит от того, насколько он лучше всего применим к вашему конкретному варианту использования.

person Tom Pelaia    schedule 31.05.2012

Отношения делегата 1-к-N не имеют смысла. Посмотри на

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row

Например. Что, если у этого объекта действительно было n делегатов? Как ему решить, какое из n представлений, полученных от всех его делегатов, следует использовать? Делегаты — это именно тот принцип 1-to-1.

NSNotificationCenter — правильный подход. Просто используйте

addObserver:selector:name:object:

соответственно

postNotification:

Это определенно не слишком много кода. И это очень легко для вас, так как центр обрабатывает все звонки.

person pbx    schedule 31.05.2012

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

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

Шаблон addDelegate/removeDelegate, который вы представляете, на мой взгляд, является полностью правильным путем, поскольку он имеет преимущество в поддержании безопасности типов и проверок компилятора и делает зависимости явными. Единственная проблема заключается в том, что Apple не предоставляет готового решения для этого шаблона, поскольку вам нужен тип коллекции, который слабо сохраняет свои элементы, чтобы избежать циклов сохранения.

Однако см. код из моего фреймворка BMCommons, который аккуратно решает эту проблему, используя BMNullableArray и макросы. См. BMCore.h для определения этих макросов:

BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)

Реализация гарантирует, что один и тот же слушатель никогда не будет добавлен дважды, а также то, что прослушиватели слабо сохраняются, не вызывая сбоев, даже если они забывают отменить регистрацию при освобождении (хотя я предпочитаю отлавливать это условие с помощью утверждения, поскольку это ошибка программирования). ).

person Werner Altewischer    schedule 24.11.2017

Я говорю, что NSNotificationCenter следует использовать ВСЕГДА поверх модели делегата, за исключением ситуаций, когда вы запрашиваете у делегата информацию (например, -webView:shouldLoadRequest:). Это более стабильно, проще в реализации и приводит к более чистому коду, чем попытка использовать делегат. Другой альтернативой являются блоки, которые могут быть хорошими, но они могут быть проблемой, когда дело доходит до управления памятью.

В конце концов, решать вам, но я думаю, что NSNotificationCenter — лучший способ практически в любой ситуации, хотя бы для функциональности нескольких наблюдателей.

person Richard J. Ross III    schedule 31.05.2012