Когда использовать 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
использоваться, а когда нет? - когда должна использоваться реализация, подобная той, которую я предлагаю здесь, а когда нет?
7 ответов
по соглашению делегаты, вероятно, должны использоваться только для отношений 1:1. Если вам действительно нужны отношения 1:N для этого типа функциональности, у вас есть два варианта:
- как вы сказали,
NSNotificationCenter
.
использование уведомлений широковещательно: 1 отправитель просто отправляет информацию, и кто когда-либо настраивался, получает ее. Петти очень похож на радиостанцию, нет канала назад (давайте на данный момент забудем о телефонах)
делегирование-это что-то другое. Объект, который просит deleagte что-то сделать, обычно нуждается в результате этого запроса, поэтому делегирование-это связь 1 к 1, которая всегда инициируется объектом, а не делегатом (в то время как объект может иметь методы, которые могут быть вызваны для информирования объекта для инициирования связи, т. е. [tableView reloadData]
).
поэтому, если отправителю нужно вернуть данные, это делегирование. Если отправитель не заботится о чем-либо после трансляции, перейдите с уведомлениями.
Если вы столкнулись с ситуацией, что вам нужно делегирование, но несколько объектов должны реализовать протокол. у вас должен быть 1 делегат, который содержит ссылки на другие объекты и вызывает методы от имени отправителей - или вы можете пойти с блоками.
NSNotificationCenter не является излишним для того, что вы предлагаете, это именно правильное решение. Это мешает наблюдаемому объекту знать или заботиться о своих наблюдателях, делая ваш код более свободно связанным и более чистым.
совместное использование строк для имен уведомлений тривиально, и они могут быть определены в файле общих констант или в заголовке наблюдаемого объекта, если наблюдателям необходимо импортировать этот заголовок для выполнения своих задач.
предлагаемое решение не проще, чем использование NSNotificationCenter, и не является потокобезопасным.
чтобы сделать поток решения безопасным, вам нужно будет предоставить механизм для предотвращения изменения массива делегатов во время выполнения цикла отправки событий.
ваше решение также требует, чтобы вы сохранить массив делегатов в своем классе. С NotificationCenter вы можете просто использовать центр по умолчанию и вам не нужно выполнять добавление / удаление методов в классе. Вместо этого экземпляры могут регистрироваться для получения уведомлений по своему усмотрению (селектор/блок, очередь, источник). Ваш исходный класс не должен беспокоиться об этих деталях. Ему нужно только зарегистрироваться в качестве источника уведомлений указанного типа. Использование блоков для обработки уведомлений действительно удобно.
альтернативой Центру уведомлений является использование Key-Value-Observing, если это соответствует потребностям вашего использования случай.
в конечном счете, механизм, который вы решите использовать, зависит от того, как лучше он относится к вашему конкретному случаю использования.
отношение делегата 1-к-N не имеет смысла. Взгляните на
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
например. Что, если у этого объекта действительно было n делегатов? Как он должен решить, какой из N представлений, которые он получает от всех своих делегатов, следует использовать? Делегаты-это именно принцип 1 к 1.
NSNotificationCenter-это правильный подход. Просто используйте
addObserver:selector:name:object:
соответственно
postNotification:
Это, безусловно, не слишком много кода. И это очень легко для вас, как центр обрабатывает все звонки.
вы не хотите использовать NSNotificationCenter для чего-либо, кроме общесистемных событий (например, появления клавиатуры или какого-либо подобного события). Причина в том, что он полностью не безопасен для типов, может сделать все зависимым от всего и что вы больше не получаете проверок времени компиляции или результатов поиска использования.
KVO, на мой взгляд, не следует использовать для наблюдения за изменениями вне объекта, который вы слушаете, так как он имеет похожие стороны вниз (без проверки времени компиляции, сбой, если вы не удалите прослушиватели должным образом или зарегистрируете их дважды).
шаблон addDelegate/removeDelegate, который вы представляете, является полностью правильным путем, на мой взгляд, поскольку это имеет преимущество поддержания безопасности типов и проверок компилятора и делает зависимости явными. Единственная проблема заключается в том, что Apple не предоставляет готовое решение для этого шаблона, поскольку вам нужен тип коллекции, который слабо сохраняет свои элементы, чтобы избежать сохранения циклы.
однако см. код из my основы BMCommons, который решает эту проблему аккуратно, используя BMNullableArray и макросы. Вижу BMCore.h для определения этих макросов:
BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)
реализация гарантирует, что один и тот же слушатель никогда не будет добавлен дважды, а также что слушатели слабо сохраняются, не вызывая сбоя, даже если они забывают отменить регистрацию при освобождении (хотя я предпочитаю поймать это условие с assert, так как это ошибка программирования).
Я говорю, что NSNotificationCenter всегда должен использоваться над моделью делегата, за исключением ситуаций, когда вы запрашиваете делегата по информации (например,-webView:shouldLoadRequest:
). Он более стабилен, проще в реализации и приводит к более чистому коду, а затем пытается использовать делегат. Другая альтернатива-блоки, которые могут быть хорошими, но они могут быть болью, когда дело доходит до управления памятью.
в конце концов, это зависит от вас, но я думаю, что NSNotificationCenter-лучший способ пойти почти в любой ситуация, хотя бы для функций множественного наблюдателя.