Знакомство с ReactiveCocoa
RACSignal Фреймворк основан на сигналах. Сигнал — это объект, в котором хранится ссылка на наблюдаемый объект и ссылки на подписчиков. Когда сигнал видит, что наблюдаемый объект изменился, он пересылает новое значение подписчикам. Подписчиком может быть другой сигнал, блок, а также любой объект.Пример 1. Сигнал, наблюдающий свойство name и передающий значения в блок:
User *user = [User new]; RACSignal *userNameSignal = RACObserve (user, name); [userNameSignal subscribeNext:^(NSString *newValue) { NSLog (@«New value: %@», newValue); }]; user.name = @«ivan»;
//Вывод в консоли: //New value: ivan
Преобразование сигналов До того, как новое значение объекта дойдет до подписчика, оно может быть подвергнуто различным преобразованиям. Такими как: изменение значения (map) фильтрация (filter, ignore) объединение с другим значением (combine) упрощение нескольких сигналов в одно (reduce) Пример 2. Продолжая первый пример, изменим передаваемое значение: User *user = [User new]; RACSignal *userNameSignal = RACObserve (user, name); [[userNameSignal map:^id (NSString *newValue) { return newValue.capitalizedString; }] subscribeNext:^(NSString *newValue) { NSLog (@«New value: %@», newValue); }]; user.name = @«ivan»;
//Теперь все значения будут передаваться подписчикам с большой буквы. //Вывод в консоли: //New value: Ivan
Биндинги Преобразования не были бы так полезны, если бы не биндинги. Они позволяют создать зависимость одного свойства от другого: Кнопка авторизации активна только если введены логин и пароль Поля ввода логина и пароля отключены, когда происходит авторизация Свойство user.isValidName меняется автоматически когда меняется свойство user.name. «Прибинженные» поля меняются сами, поэтому не надо в коде следить за актуальными значениями. Это полезно, например, в приложениях со сложной логикой интерфейса.Продолжая предыдущий пример, сделаем биндинг для свойства user.login, чтобы подходящий логин автоматически предлагался пользователю на основе имени:
RAC (user, login) = [userNameSignal map:^id (NSString *name) { return [name stringByReplacingOccurrencesOfString:@» » withString:@»_»].lowercaseString; }]; user.name = @«Vladimir Petrov»; NSLog (@«Login: %@», user.login);
// Вывод в консоли: // Login: vladimir_petrov
Минусы Начав использовать ReactiveCocoa, уже трудно представить разработку без него. Но у этого фреймворка есть минусы, которые для кого-то могут быть существенными: Частое использование KVO может снизить производительность. Решается оптимизацией и неиспользованием RAC’a в высоконагруженных участках кода. Сложная отладка из-за частого использования блоков, особенно внутри самого ReactiveCocoa. Порой в поиске ошибки помогает лишь интуитивное понимание objective-c. Легко допустить ошибку и они приводят к неожиданным последствиям. Перегруженный синтаксис. Этой проблемы не будет с переходом на swift. В заключение Описанное выше — лишь малая часть того, что может ReactiveCocoa. Однако, даже применив только это, можно заметно упростить свою работу. Если эта статья будет кому-нибудь интересна, в следующей можно будет разобрать более сложные и интересные части этого фреймворка.