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

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

>Мы уже привыкли описывать (бизнес) логику во ViewController. И это настоящий ад.
Это потому, что в MVC бизнес логику нужно описывать в модели.
Согласен. Видимо я выразился некорректно.
Но от того, что работа с данными, сетью и т.д. и т.п. остается в моделях, контроллеры от этого не становятся менее уродливыми. Скорее всего этому способствует масса материала, где показывается решение задачи в лоб, и начинающий разработчик её воспринимает как должное, не пытаясь как-то раскидать все по своим местам. Со временем у него накапливается такой опыт проект оказывается неподдерживаемым. Видимо я сам попал в такую ситуацию, но решение нашлось уже на другой стороне :)
Просто ViewController это все таки V в MVC.
Кто не согласен? Готов аргументировать.
Не я поставил минус, но тоже не согласен.
Аргументируйте, и за одно расшифруйте остальные символы в аббревиатуре.
UIViewController в iOS выполняет исключительно связанные с View обязанности, повороты, appear/dissappear, navigation и прочее. То, что туда суют взаимодействие с моделью приводит к другой расшифровке MVC = Massive View Controller. Все с этим сталкивались. Принятие того, что UIViewController это часть View и переход к шаблону MVVM оставляет за ViewController именно те обязаности которые описаны в интерфейсе базового класса. Вот отличная статья на эту тему.
Я понял Вашу шутку, но связи между
Просто ViewController это все таки V в MVC.

и
MVC = Massive View Controller

не вижу.
Если мы говорим о переходе к шаблону MVVM, то ViewController будет в нем ViewModel, предоставляя для View все необходимые данные в нужном формате. Мы ведь сами в storyboard/xib однозначно соединяем представлением с тем или иным классом. В ViewController действительно не должно быть кода, из которого понятно от куда данные пришли и что пользователь/приложение с ними делает.

View — это xib или storyboard хоть в MVC, хоть в MVVM.

Наглядней всего MVVM реализована в Windows Phone (Silverlight). Советую как-нибудь попробовать, мозги переворачиваются после iOS.
Проблема не в MVC, а в игнорировании паттерна и превращения кода в мясо. Использование другого паттерна не решает проблему того, что этот паттерн тоже игнорируется и код превращяется в неподдерживаемое месево. Вся бизнес логика должна отделяться от MVC, MVVM и прочих букв этого семейства. Бизнес логика дожна жить самостоятельно. Контроллер в MVC должен заниматься контролем и не заниматься обязанностями представления (максимум — делегировать представлению).
Так и есть :) Когда писал свой пост, то мои знания были ограничены лишь MVC паттерном и тем, как он применяется в современных веб фреймворках. Но недавно наткнулся на блог Роберта Мартина (Uncle Bob) и прозрел…
Не прошла затравка (((
Чего у Вас не хватает в классе Dynamic, так это методов: unBind и removeListener.
Иногда ведь нужно отменять подписку не дожидаясь своей смерти (освобождения памяти).
Наличие этих методов также решает проблему weak, unowned в замыканиях (closures), которые используются в качестве коллбэков. Используете unowned, а в методе deinit вызываете removeListener или unBind.
Изначально паттерн Observer подразумевает симметричность вызовов add/remove.
Появляется дополнительная строчка кода, это да, но как по мне, гонясь за локоничностью, Вы можете потерять логичность.

В целом статья хорошая, расширяет понимание возможностей swift.
А с потоками такой подход будет работать? Т.е. у нас нечто будет хранить target (ссылка на объект) и callback. При необходимости оповестить слушателей (targets) мы сначала проверяем существование этого target, затем либо удаляем его из списка, либо дергаем callback. Так вот если target удалился в одном потоке, а в этот момент в другом потоке возникла необходимость подергать callback'и, то можно быть уверенным, что все пройдет гладко?
При необходимости оповестить слушателей (targets) мы сначала проверяем существование этого target, затем либо удаляем его из списка, либо дергаем callback.

Вы не можете проверить существование target либо другого объекта, так как при обращении к объекту, который освобожден из памяти, мы получим крэш. Это, если я правильно понял смысл слова «проверяем существование target».
Я предлагал, чтобы target сам добавлялся и удалялся из подписки, когда ему нужно. Обычно это выполняется в методах init и deinit.
Чтобы с несколькими потоками все было гладко, нужно обеспечить потокобезопасный доступ к списку, который хранит слушателей.
Судя по всему аналога atomic в swift нет.
Видел такой вариант реализации потокобезопасности:
objc_sync_enter(self.targets)
self.targets.removeAtIndex(index)
objc_sync_exit(self.targets)
Вы не можете проверить существование target либо другого объекта, так как при обращении к объекту, который освобожден из памяти, мы получим крэш. Это, если я правильно понял смысл слова «проверяем существование target».

Представлял это как-то так:
class SimpleDynamic<T> {
  private weak var target: AnyObject?
  private var listener: T -> Void
  init(value: T, target: AnyObject, listener: T -> Void) {
    self.value = value
    self.target = target
    self.listener = listener
  }
  var value: T {
    didSet {
      if target != nil {
        listener(value)
      }
    }
  }
}

По-моему проверка на nil должна работать. Во всяком случае где-то уже подобное видел.
Насчет самостоятельной подписки и отписки: не хотелось бы, чтобы разработчик держал в голове второй пункт.
Насчет потокобезопасности. Да, такое уже есть в Bond, только сегодня заметил. Именно Ваш вариант.
Значит изначально я все-таки вас неправильно понял.
В таком варианте да, нужно проверять на nil.
Получается, target хранится как weak, то есть как Вы хотели — не нужно заботиться о втором пункте.
В теле listener можно спокойно использовать self как unowned, так как механизм гарантирует вызов замыкания только пока self жив.
Ну и потокобезопасность добавить.
Но наличие методов unBind и removeListener я бы все же оставил, так как иногда действительно нужно отписаться где-то в середине жизненного цикла подписчика.
Но наличие методов unBind и removeListener я бы все же оставил, так как иногда действительно нужно отписаться где-то в середине жизненного цикла подписчика.

Без этого никуда :) Благодарю за советы.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.