Как стать автором
Обновить

Комментарии 12

А почему Combine не подошёл? Я бы в источнике завёл приватный PassThroughValue + публичный метод подписки на него.

Вероятно у вас даже получилось бы примерно то же самое, но с массивной и сравнительно медленной (backpressure management) инфраструктурой и внешней зависимостью от Combine. Если вам нужна backpressure, пожалуйста - пользуйтесь Combine.

А еще кажется, что KVO, property wrappers и даже observer blocks (те самые didSet, willSet) тоже являются различными реализациями паттерна наблюдатель, но в статье они не рассмотрены даже бегло, как и реализации в Combine.

KVO да, но им пользоваться крайне неудобно и к тому же вы ограничены только objc классами. И не ко всем свойствам применимо KVO, а только к KVO compliant. Property Wrappers и Property Observers имеют весьма отдалённое отношение к обсуждаемой теме.

Спасибо за статью. Качественно.
Только, наверное, стоит отметить в статье, что каждый инструмент нужно использовать по назначению, а не пробовать построить универсальный молоток под саморезы и шурупы.
В частности, необходимо отметить, что тот же `addTarget:` задумывался под конкретную цель. А именно -- работу с responder chain. Попытки заменить `addTarget:` на ваш "идеальный наблюдатель" приведут к необходимости дублировать экшены из контроллера в контроллер, из вьюхи во вьюху или же добавят сильной связности между ними, если вдруг вы попытаетесь не дублировать экшены, а прокидывать их между перечисленными классами.

Совершенно необоснованный вывод о заточке под "конкретно работу с responder chain" - в UIControl вполне успешно работает классический подход. Представленное решение скорее децентрализованная альтернатива для NotificationCenter. У NC - есть ещё один минус. Либо использовать @obj-c методы либо обязательная ручная отписка. Основной же прицел был представить качественную альтернативу самописным MulticastDelegate. Я несколько раз с ними встречался в различных проектах и каждый раз это было унылым г-кодом.

Очень даже обоснованный. Responder chain, как раз то, что делает addTarget: таким мощным средством. Как выглядит типичный роутинг в 90% iOS приложений? Правильно: одни и те же экшены в каждом контроллере, из которого необходимо открывать, например, одно и то же модальное окно. Теперь как это можно улучшить воспользовавшись Responder chain:
1. Оставляем лишь один action
2. Переносим его в контейнер контроллер, например в таббар-контроллер.
3. В addTarget указываем nil вместо конкретного контроллера, в котором находится UI-элемент, к которому подключается подписка.
4. В принципе все. Из-за того, что мы не указали конкретный таргет, отправка нотификации уходит по Responder chain и доходит от каждого конкретного контроллера до таббар-контроллера и показывается то самое необходимое модальное окно. Только action теперь в едином экземпляре со всеми вытекающими. Данный подход перенесен на iOS из Mac, в котором он использовался для работы с командами меню. Если проследить аналогии, то понятно, что команда должна быть одна, а вот вызываться она может, когда совершенно разные UI-элементы и целые окна могут быть активны. Именно этим и надо пользоваться в iOS.

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

Непонятна ваша настойчивость. Observer - универсальный шаблон проектирования. Из набора GOF. Если Responder Chain (тоже из GOF) прекрасно работала и без моего Observer, зачем пытаться натягивать Сову на Глобус Observer на ResponderChain?
Уже писал: подумайте об Observer когда вам нужен NotificationCenter или что-то похожее.

Вот хорошая статья для ознакомления, как можно сделать неплохой наблюдатель на Свифт: https://www.swiftbysundell.com/articles/first-class-functions-in-swift/. Удовлетворяет всем критериям, что вы обозначили? Проведете сравнение вместе с остальными нативными реализациями наблюдателя и добавите в статью, чтобы она получилась всеобъемлющей?

Статья на которую вы ссылаетесь описывает возможности функций в Swift. B качестве иллюстрации там приведён полуфункциональный пример add(target:, action). Без возможности удаления слушателей как в UIControl и без поддержки responder chain. Да ещё с избыточной заумью.
В статье target.map(action)?(view) можно заменить на target?.action(view). Всем моим критериям пример из статьи не удовлетворяет. (Например нет возможности удаления слушателей - а если добавить она будет неэффективной). В моей статье есть краткое сравнение с UIControl и NotificationCenter. Кажется, этого достаточно. Моя статья не имела целью раскрывать возможности функций в языке Swift. Этому посвящено множество других метриалов, в том числе тот на который вы ссылаетесь.

public static func += (event: Event, observer: Observer)
один и тот же observer может добавится много раз

не понимаю зачем использовать LinkedList, Set тут выигрывает по всем параметрам.

Set прекрасен, но требует чтобы добавляемые в него элементы были Hashable. К сожалению, функции, замыкания и методы классов нельзя хэшировать. Что делает его непригодным для применения в нашем случае.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий