Здравствуйте, Святослав )
Времени статьи отняли конечно порядочно, но просто захотелось хоть немного вернуть долг сообществу. Ведь сколько было за эти годы прочитано статей. Есть время разбрасывать камни, и время собирать камни )
Спасибо Вам за ответы.
По поводу вопросов 2 и 3. Для 3ей статьи я как раз создал приложение имеющее идентичный функционал но с разными архитектурными подходами. Производительность правда там особо не померяешь, не те нагрузки. А вот по поводу веса вполне можно было бы сказать, но нужно делать полноценный билд для App Store, там же собирается «по уму», то что не нужно отрезается и все в таком духе.
4) Золотые слова. Я как раз слишком увлекся Rx-фикацией, когда пытался сделать clear Rx везде где только можно. Урок был усвоен )
В последнее время я заинтересовался immutable моделями, судя по WWDC 2016, Apple тоже стала её продвигать. Но тут своих нюансов тоже хватает, как и в Rx. Если в итоге паззл в голове сложится — будет и 3я статья )
Рад, что мои статьи действительно помогают, а не просто осели в избранном )
До юнит тестов у меня руки не дошли (планировал 4й в цикле статей), так что Ваша статья — очень нужна.
К сожалению 3я статья в состоянии «заморозки», она была посвящена архитектурным решениям RxSwift в сравнении с другими (MVC, MVVM без RxSwift). Но в процессе написания пришло понимание, что у меня не хватает времени и опыта практической работы с RxSwift, чтобы написать действительно достойный материал, а писать «чтобы было» не хочется.
В комментариях к другой статье по RxSwift я попробовал попытать автора на интересовавшие меня вопросы, но обьем текста в вопросах стал приближаться к обьему написанной им статьи и общение как то сошло на нет )
Так что сделаю еще одну попытку затронуть интересующие темы, если позволите.
1) Вы, я так понимаю, активно применяете RxSwift в production коде. Это приложения для клиентов или для себя? Если для клиентов — как они смотрят на то, что код будет «нестандартным»?
2) Не сталкивались ли с проседанием производительности в RxSwift?
3) Сколько добавляет в весе использование RxSwift в релизе?
4) RxSwift используется повсеместно во всем приложении или в основном для GUI привязок?
Просто RxSwift подразумевает под собой реализацию парадигмы функционально-реактивного программирования, которая включает в себя неизменяемость, что довольно тяжело выполнить везде. Достаточно посмотреть на их попытку продемонстрировать работу с TableView в RxSwift (TableViewWithEditingCommands).
Так что часто приходится в VM использовать изменяемые модели.
А вообще беда в том, что технология все же еще молода, и нет нормально выкристализованных best practice. Хотя мне очень понравилось работать с RxSwift, так что через время наверное сделаю еще одну попытку.
Не знаю в тему ли будет мой ответ по наушникам, но поделюсь опытом. Очень хорошей звукоизоляцией (именно изоляцией, шумодава в них нет) обладают Beyerdynamic dt 770 pro, поэтому я собственно их и выбрал, это по сути полупроф наушники, часто вижу их на фотках у радиоведущих. Я же работаю дома, рядом дети, и это в плане шумов будет похлеще любого офиса. Действительно спасают, если отвлекает музыка — включается шум дождя и растворяешься в коде (природный шумодав).
Так же огромным преимуществом (для меня так точно) — являются велюровые амбушюры, просто практически у всех наушников со звукоизоляцией используется кожа или что то вроде того, и после часа работы уши оказываются в жаркой бане.
Минусом наверное можно назвать цену, но если смотреть сетап из статьи, лишние 15 тысяч, вроде особой погоды не сыграют.
Правда после покупки они мне прилично давили, на ночь поставил на растяжку и с тех пор никаких проблем.
Ну я поэтому и сказал, что решать только в частном порядке.
Учитывая что идет сравнение по адресу памяти — крайне сомневаюсь, что получится что то сделать. Если бы была такая возможность, — просто представьте какие возможности это открыло бы перед злоумышленниками.
Это бы означало, что все обязаны знать про Rx, я думаю авторы других библиотек не особо обрадуются такому повороту.
Скорее если уж вводить общий API — определить, что если мы подменяем delegate то у прокси обязательно должен быть метод oldDelegate() -> NSObject
И каждая библиотека пусть при подмене делегата смотрит — есть ли такой метод, если есть — рекурсивно получает делегат, и если в итоге понимает что она уже есть где то глубже — ничего не подменять.
Но тут две проблемы.
1) это же надо ввести как стандарт, заставить авторов это реализовать
2) для какой то библиотеки может быть не критично насколько глубоко она стоит в иерархии oldDelegate, а для какой то обязательно надо быть первой. И рано или поздно найдутся библиотеки для которых кровь из носу надо быть первыми. И мы получим ту же проблему.
В общем каждый случай нужно рассматривать отдельно.
Для конкретных двух библиотек решение найти не проблема, вопрос в том как решить в общем виде. Ведь таких библиотек может быть и 20, в каждую вносить знание о каждой — никто не станет даже браться.
Приводить к единому стандарту? Опять таки вряд ли кто займется.
С удовольствием почитаю. Статья основанная на успешном опыте будет крайне кстати.
Если вкратце, — MVVM?
Я вот сейчас как раз думаю как по уму это все применить. MVVM, + вынес все таки роутер из ViewController'а. Не очень нравится, что из VM в какой то мере получается god объект, он хоть и делегирует все сервисам, но все таки это уже не совсем чистый VM. Думаю как грамотно распилить VM и стоит ли это делать.
Ну то, что прокси переустанавливается при несоответствии при каждой Rx манипуляции было в принципе освещено в статье в комментариях к содержимому функции proxyForObject
По поводу того баг ли это или нет я затрудняюсь сказать. Точнее понятно, что это потенциальная проблема. Но вот как решить. Можно дать возможность настраивать ядро Rx, чтобы какие то классы и их производные не перезаписывались проксей (в надежде что они уже выставили нашу прокси как свой forwardToDelegate). Не самый лучший подход. Можно кешировать rx_delegate, но тогда нужно следить за временем жизни прокси самому, ну или если после этого сверху что то было навернуто посредством BlocksKit, то наша прокси будет об этом не знать и все будет пролетать мимо BlocksKit. В общем простого решения нет, причем это не проблема Rx, а в принципе библиотек которые вмешиваются в работу runtime'а
Ведь в таком случае баг можно постить и на пресловутый BlocksKit.
Стоит посмотреть на реализацию в _RXDelegateProxy.m. Если вкратце, — при создании прокси извлекаются все доступные методы и выставляются в качестве доступных. Так же в _RXObjcRuntime.m производится swizzle методов отвечающих за диспетчеризацию.
Таким образом при возникновении события — отрабатывает перехватчик из _RXDelegateProxy
subjectsForSelector же заполняется нужными сигнатурами, только когда мы делаем observe для delegate прокси.
public func observe(selector: Selector) -> Observable<[AnyObject]> {
if hasWiredImplementationForSelector(selector) {
print("Delegate proxy is already implementing `\(selector)`, a more performant way of registering might exist.")
}
if !self.respondsToSelector(selector) {
rxFatalError("This class doesn't respond to selector \(selector)")
}
let subject = subjectsForSelector[selector]
if let subject = subject {
return subject
}
else {
let subject = PublishSubject<[AnyObject]>()
subjectsForSelector[selector] = subject
return subject
}
}
Таким образом подписываемся мы вроде на все события, но DelegateProxy обрабатывает лишь те на которые есть подписка.
Далее вне зависимости от того отработал код в DelegateProxy или нет — если в _RXDelegateProxy есть forwardToDelegate — событие отправляется уже в оригинальный делегат
Вот как раз над этим сейчас и работаю. Перебираю возможные реализации. Т.к. к сожалению даже в Rx примерах архитектура на мой взгляд говоря не ахти, хоть там и заявлен MVVM, но создавать из ViewController — ViewModel, причем передавая в инициализацию сервисы — так себе идея. Ищу баланс между чистотой кода, расширяемостью и количеством классов на отдельный юнит.
Я пока сам определяюсь буду ли использовать и в каком виде Rx в своих приложениях. Надо хотя бы на парочке pet проектов опробовать, потом уже делать выводы.
P.S. Да читаем мы теги, читаем )
Времени статьи отняли конечно порядочно, но просто захотелось хоть немного вернуть долг сообществу. Ведь сколько было за эти годы прочитано статей. Есть время разбрасывать камни, и время собирать камни )
Спасибо Вам за ответы.
По поводу вопросов 2 и 3. Для 3ей статьи я как раз создал приложение имеющее идентичный функционал но с разными архитектурными подходами. Производительность правда там особо не померяешь, не те нагрузки. А вот по поводу веса вполне можно было бы сказать, но нужно делать полноценный билд для App Store, там же собирается «по уму», то что не нужно отрезается и все в таком духе.
4) Золотые слова. Я как раз слишком увлекся Rx-фикацией, когда пытался сделать clear Rx везде где только можно. Урок был усвоен )
В последнее время я заинтересовался immutable моделями, судя по WWDC 2016, Apple тоже стала её продвигать. Но тут своих нюансов тоже хватает, как и в Rx. Если в итоге паззл в голове сложится — будет и 3я статья )
До юнит тестов у меня руки не дошли (планировал 4й в цикле статей), так что Ваша статья — очень нужна.
К сожалению 3я статья в состоянии «заморозки», она была посвящена архитектурным решениям RxSwift в сравнении с другими (MVC, MVVM без RxSwift). Но в процессе написания пришло понимание, что у меня не хватает времени и опыта практической работы с RxSwift, чтобы написать действительно достойный материал, а писать «чтобы было» не хочется.
В комментариях к другой статье по RxSwift я попробовал попытать автора на интересовавшие меня вопросы, но обьем текста в вопросах стал приближаться к обьему написанной им статьи и общение как то сошло на нет )
Так что сделаю еще одну попытку затронуть интересующие темы, если позволите.
1) Вы, я так понимаю, активно применяете RxSwift в production коде. Это приложения для клиентов или для себя? Если для клиентов — как они смотрят на то, что код будет «нестандартным»?
2) Не сталкивались ли с проседанием производительности в RxSwift?
3) Сколько добавляет в весе использование RxSwift в релизе?
4) RxSwift используется повсеместно во всем приложении или в основном для GUI привязок?
Просто RxSwift подразумевает под собой реализацию парадигмы функционально-реактивного программирования, которая включает в себя неизменяемость, что довольно тяжело выполнить везде. Достаточно посмотреть на их попытку продемонстрировать работу с TableView в RxSwift (TableViewWithEditingCommands).
Так что часто приходится в VM использовать изменяемые модели.
А вообще беда в том, что технология все же еще молода, и нет нормально выкристализованных best practice. Хотя мне очень понравилось работать с RxSwift, так что через время наверное сделаю еще одну попытку.
Так же огромным преимуществом (для меня так точно) — являются велюровые амбушюры, просто практически у всех наушников со звукоизоляцией используется кожа или что то вроде того, и после часа работы уши оказываются в жаркой бане.
Минусом наверное можно назвать цену, но если смотреть сетап из статьи, лишние 15 тысяч, вроде особой погоды не сыграют.
Правда после покупки они мне прилично давили, на ночь поставил на растяжку и с тех пор никаких проблем.
Учитывая что идет сравнение по адресу памяти — крайне сомневаюсь, что получится что то сделать. Если бы была такая возможность, — просто представьте какие возможности это открыло бы перед злоумышленниками.
Скорее если уж вводить общий API — определить, что если мы подменяем delegate то у прокси обязательно должен быть метод oldDelegate() -> NSObject
И каждая библиотека пусть при подмене делегата смотрит — есть ли такой метод, если есть — рекурсивно получает делегат, и если в итоге понимает что она уже есть где то глубже — ничего не подменять.
Но тут две проблемы.
1) это же надо ввести как стандарт, заставить авторов это реализовать
2) для какой то библиотеки может быть не критично насколько глубоко она стоит в иерархии oldDelegate, а для какой то обязательно надо быть первой. И рано или поздно найдутся библиотеки для которых кровь из носу надо быть первыми. И мы получим ту же проблему.
В общем каждый случай нужно рассматривать отдельно.
Приводить к единому стандарту? Опять таки вряд ли кто займется.
Жду статью )
Если вкратце, — MVVM?
Я вот сейчас как раз думаю как по уму это все применить. MVVM, + вынес все таки роутер из ViewController'а. Не очень нравится, что из VM в какой то мере получается god объект, он хоть и делегирует все сервисам, но все таки это уже не совсем чистый VM. Думаю как грамотно распилить VM и стоит ли это делать.
По поводу того баг ли это или нет я затрудняюсь сказать. Точнее понятно, что это потенциальная проблема. Но вот как решить. Можно дать возможность настраивать ядро Rx, чтобы какие то классы и их производные не перезаписывались проксей (в надежде что они уже выставили нашу прокси как свой forwardToDelegate). Не самый лучший подход. Можно кешировать rx_delegate, но тогда нужно следить за временем жизни прокси самому, ну или если после этого сверху что то было навернуто посредством BlocksKit, то наша прокси будет об этом не знать и все будет пролетать мимо BlocksKit. В общем простого решения нет, причем это не проблема Rx, а в принципе библиотек которые вмешиваются в работу runtime'а
Ведь в таком случае баг можно постить и на пресловутый BlocksKit.
RxSwift/RxCocoa/Common/_RXDelegateProxy.m
RxSwift/RxCocoa/Common/_RXObjcRuntime.m
Поиском на гитхабе в репозитории RxSwift находится без проблем
Таким образом при возникновении события — отрабатывает перехватчик из _RXDelegateProxy
Если сигнатура метода есть в нашем списке — вызывается interceptedSelector уже для DelegateProxy
subjectsForSelector же заполняется нужными сигнатурами, только когда мы делаем observe для delegate прокси.
Таким образом подписываемся мы вроде на все события, но DelegateProxy обрабатывает лишь те на которые есть подписка.
Далее вне зависимости от того отработал код в DelegateProxy или нет — если в _RXDelegateProxy есть forwardToDelegate — событие отправляется уже в оригинальный делегат