Ваше мнение об этой альтернативе уведомлениям и делегатам: Сигналы? - PullRequest
4 голосов
/ 24 января 2011

ТАК говорит мне, что этот вопрос субъективен и, вероятно, будет закрыт.Это действительно субъективно, потому что я спрашиваю мнение опытных разработчиков Objective-C.Должен ли я опубликовать это где-то еще?Пожалуйста, сообщите.


Совершенно новый для Objective-C, хотя и довольно уверенный в концепции написания кода ООП, я с самого начала боролся с дилеммой NSNotification vs Delegate.Я написал несколько вопросов на эту тему в одиночку.Я понимаю суть, я думаю.Уведомления передаются по всему миру, поэтому их не следует использовать для уведомления о тесно связанных объектах.Делегаты существуют для передачи задач другому объекту, который действует от имени делегированного объекта.Хотя это может быть использовано для тесно связанных объектов, я нахожу рабочий процесс многословным (новый класс, новый протокол и т. Д.), И одно только слово «делегирование» заставляет меня думать об армиях и начальстве и в целом заставляет меня чувствовать себя неловко.

Откуда я (AS3), есть вещи, называемые событиями.Они на полпути между делегатами и NSNotifications и в значительной степени управляли миром флеш-уведомлений, пока совсем недавно не появился мистер Роберт Пеннер и не выразил свое недовольство событиями.Поэтому он написал библиотеку, которая сейчас широко используется в сообществе AS3, под названием Signals.Вдохновленные событиями C # и Сигналами / Слотами в Qt, эти сигналы на самом деле являются свойствами объектов, к которым вы обращаетесь извне и добавляете слушателей.С сигналом можно сделать гораздо больше, но по сути это все.

Поскольку концепция настолько скромна, я попробовал и написал свой собственный класс сигналов в Objective-C. Я указал здесь Signal.h / .m .

Способ использования этого для уведомления класса A о событии в классе B может выглядеть следующим образом:

// In class b, assign a Signal instance to a retained property:
self.awesomeThingHappened = [[[Signal alloc] init] autorelease];

// In class a, owner of class b, listen to the signal:
[b.awesomeThingHappened add:self withSelector:@selector(reactToAwesomeThing)];

// And when something actually happens, you dispatch the signal in class b:
[self.awesomeThingHappened dispatch];

// You might even pass along a userInfo dictionary, your selector should match:
[self.awesomeThingHappened dispatchWithUserInfo:userInfo];

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

Мой вопрос для stackoverflow заключается в том, чтовы думаете о решении, как это?Вы бы мгновенно удалили это из своего проекта, если бы один из ваших стажеров включил его?Вы бы уволили своего сотрудника, если он уже закончил свою практику?Или, может быть, уже есть что-то подобное, но гораздо более грандиозное, что вы бы использовали вместо этого?

Спасибо за ваше время, EP.


РЕДАКТИРОВАТЬ: Позвольте мне датьконкретный пример того, как я использовал это в проекте iOS.

Рассмотрим этот сценарий четырех типов объектов с вложенным владением.Есть контроллер представления, владеющий оконным менеджером, владеющий несколькими окнами, каждое из которых имеет представление с элементами управления, среди которых кнопка закрытия.Возможно, здесь есть недостаток дизайна, но это не главное в примере: P

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

Уведомления от окна до оконного менеджера и от оконного менеджера до контроллера просмотра - это те, которые я сейчас реализовал с помощью сигналов.Это могло бы быть делом делегирования, но для всего лишь «близкого» действия создание двух делегированных протоколов казалось настолько многословным.С другой стороны, поскольку связь этих объектов очень хорошо определена, это также не похоже на случай с NSNotifications.На самом деле, с KVO я также не могу наблюдать изменения значения, потому что это просто нажатие кнопки.Прослушивание какого-то «скрытого» состояния заставило бы меня сбросить этот флаг только при повторном открытии окна, что затрудняет его понимание и приводит к небольшим ошибкам.

Ответы [ 4 ]

2 голосов
/ 27 января 2011

Хорошо, после небольшого объединения ответов и комментариев, я думаю, что пришел к выводу, что у класса Сигнала, который я позаимствовал у AS3, очень мало причин для существования в Objective-C / Cocoa. В Какао есть несколько шаблонов, которые охватывают области применения, которые я думал охватить классом Signal. Это может показаться очень тривиальным для более опытных разработчиков Cocoa, но для меня было трудно получить полный спектр.

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

Target-Action

Используется только для уведомления вашего приложения о взаимодействии с пользователем (чаще всего касается). Из того, что я видел и читал, нет способа «одолжить» систему целевого действия для собственного использования

КВО (соблюдение ключевого значения)

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

NSNotification

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

Делегирование

Занимает наибольшее количество строк кода по сравнению с остальными тремя, но также наиболее подходит, когда остальные три - нет. Используйте этот, когда один объект должен быть уведомлен о определенных событиях в другом. Не следует злоупотреблять делегатами за простой доступ к методам объекта-владельца. Придерживайтесь таких методов, как «следует», «будет» и «сделал».

Сигнал

Это был забавный эксперимент, но я в основном использовал его для классических ситуаций делегирования. Я также использовал его для обхода связанных делегатов (c делегат b, b делегат a, где a запускает событие, которое должно сделать это c), не желая прибегать к NSNotification.

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

1 голос
/ 25 января 2011

Это интересная идея, но, думаю, я не понимаю, чем она сильно отличается от центра уведомлений Какао. Сравните и сопоставьте:

self.awesomeThingHappened = [[[Signal alloc] init] autorelease];                  // Your signals library
                                                                                  // Cocoa notifications (no equivalent code)

[b.awesomeThingHappened add:self withSelector:@selector(reactToAwesomeThing)];    // Your signals library
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(reactToAwesomeThing:)
                                             name:@"AwesomeThingHappened"
                                           object:n];                             // Cocoa notifications

[self.awesomeThingHappened dispatch];                                             // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:@"AwesomeThingHappened"
                                                    object:self];                 // Cocoa notifications

[self.awesomeThingHappened dispatchWithUserInfo:userInfo];                        // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:@"AwesomeThingHappened"
                                                    object:self
                                                  userInfo:userInfo];             // Cocoa notifications

Итак, хорошо. Я не думаю, что вы пытаетесь сказать, что строка за строкой, библиотека сигналов для какао отличается ; скорее, аргумент гласит, что это термины связывание , это не так тесно, как делегаты, но не так свободно, как уведомления. С этой целью, я думаю, мне интересно, насколько это необходимо? Я предполагаю, что вижу необходимость сказать «этот объект« A »сильно зависит от« B », но его не нужно слишком тесно связывать», но, честно говоря, это кажется довольно редкой ситуацией.

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

Трудно сказать больше без конкретного случая использования. Я склонен сказать: «Эй, это круто выглядит вызывающе, но похоже, что оно выполняет роль, уже обслуживаемую уведомлениями». Есть ли у вас какие-либо конкретные случаи использования, которые вы могли бы привести?

0 голосов
/ 11 февраля 2015

Я думаю, что - это разрыв между NSNotifications и Делегатами. И у KVO есть худший API во всем Какао .

Что касается NSNotificationCenter, вот некоторые из его проблем:

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

Так что определенно нужно что-то лучшее.

Я создал свой собственный наблюдаемый класс , который я использую в каждом проекте. Другой альтернативой является использование ReactiveCocoa RACSignal .

0 голосов
/ 24 января 2011

Что вы думаете о подобном решении?

Я не понимаю, в чем выгода.На мой взгляд, это похоже на сочетание цели / действия + уведомлений (вы можете иметь несколько целей / действий для одного события уведомления, но пара t / a зарегистрирована в самом объекте, а не в глобальном центре уведомлений).Фактически, это больше похоже на наблюдение значения ключа таким образом, за исключением того, что KVO ограничен наблюдаемыми свойствами.

Вы бы сразу стерли это из своего проекта, если его вставил один из ваших стажеров?

Нет.Это не плохой код.На самом деле, это выглядит довольно аккуратно.Но я не вижу в этом очевидной выгоды.

Вы бы уволили своего сотрудника, если он уже закончил свою стажировку?

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

Может быть, есть что-то подобное, но гораздо более грандиозное, что вы бы использовали вместо этого?

Если вы действительнохотел сделать это аккуратно, измените API, чтобы использовать блоки вместо.Тогда вы можете сделать:

[object dispatchOnAwesomeThingHappened:^{
  NSLog(@"holy cow, something awesome just happened!");
}];

Опять же, вы будете ограничены реакцией на вещи, которые объекты явно "отправляют".Было бы намного лучше, если бы вы могли прикрепить материал непосредственно перед и / или после любого произвольного вызова метода.Если вам это интересно, я бы проверил Aspect Objective-C на github .

...