13

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

Механизм для достижения этой задачи предоставляется 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-в-N (например, события C#) в iOS-каркасе, кроме NSNotificationCenter?
  • Когда следует использовать NSNotificationCenter, а когда нет?
  • Когда должна быть реализована реализация, подобная той, которую я предлагаю здесь, а когда нет?
+0

Я редко или никогда не использовал NSNotificationCenter, но пошел тем же методом, который вы описываете. Я использовал это в многочисленных приложениях iOS (скажем, более 50 приложений) в течение многих лет, я пока не видел никаких проблем с этим. Возможная добыча может заключаться в том, что вы должны быть уверены, что время от времени удаляете наблюдателей, или они могут не освобождаться, когда ожидаются, потому что они сохраняются хранителем делегатов. – Jonny

+0

Я думаю, что хотя NSNotificationCenter - это не тот подход, который мы знаем из C#, мы все равно должны сосредоточиться на использовании шаблонов проектирования для конкретной платформы, над которой мы работаем. Тем не менее, я пошел с NSNotificationCenter в нескольких приложениях (не так много, как вы, хотя), и я не думаю, что код стал хуже благодаря этому. – Etan

ответ

14

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

  1. Как вы упомянули, NSNotificationCenter.
  2. Key-Value Observing (также известный как KVO).

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

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

+0

Можете ли вы сказать мне, правильно ли я использую его? http://stackoverflow.com/questions/42111829/share-object-state-between-view-controllers-in-ios-development/42113389#42113389 –

-3

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

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

1

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

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

0

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

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

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

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

addObserver:selector:name:object: 

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

postNotification: 

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

2

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

Делиться чем-то другим. Th-объект, который запрашивает у deleagte что-то делать, обычно нуждается в результате этого запроса, поэтому делегирование - это сообщение 1 к 1, которое всегда инициируется объектом, а не делегатом (в то время как объект может иметь методы, которые может быть вызван, чтобы сообщить объекту инициировать сообщение, то есть [tableView reloadData]).

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

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

+0

Сегодня у меня будет только один объект, который все VCs разделяют и сообщают им. – vikingosegundo

1

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

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

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

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

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

0

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

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

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

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

BM_LISTENER_METHOD_DECLARATION(protocol) 
BM_LISTENER_METHOD_IMPLEMENTATION(protocol) 

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