Сегодня хотелось бы поговорить о работе с потоками в ReactiveCocoa. Я не буду вдаваться в подробности основ фреймворка и полагаю, что вы уже знакомы с базовыми принципами реактивного программирования в iOS.
Работа с потоками в мобильном приложении наиважнейшая тема и это все знают. Стандарнтыми инструментами для этого, являются GCD или NSOperation. Но при использовании ReactiveCocoa в нашем проекте, все становится несколько иначе. Нет, вам никто не запрещает использовать стандартные инструменты, но зачем? Мы в каждый блок будем пихать GCD? Для этого в ReactiveCocoa придумали весьма удобную реализацию.
Для работы с многопоточностью в ReactiveCocoa существует класс RACScheduler. По сути, это обертка над GCD… и имеет те же самые приоритеты потоков, что и у GCD:
Рассмотрим основные методы RACScheduler, которые могут нам понадобиться при работе с ним:
Из названия, в принципе, становится ясно, что нам возвращается RACScheduler, который будет выполнять работу в главном потоке.
В данном случае, нам возвращается RACSCheduler с указанным приоритетом и уже не в главном потоке.
Возвращает RACScheduler c приоритетом RACSchedulerPriorityDefault.
Возвращает текущий RACScheduler из текущего NSThread.
Блок, который RACSCheduler может выполнить где угодно. И к этому мы еще вернемся.
Далее приведу основные функции для RACSignal, которые могут использоваться нами для управления многопоточностью: Данный метод RACSignal, говорит о том, что блоки получения новых значений в subscribeNext/doNext/subscribeError/etc. будут выполняться в том RACSCheduler, который мы вернем.
Данный метод RACSignal, говорит о том, в каком RACScheduler будет выполняться блок, созданный при создании подписки (если мы говорим про ReactiveCocoa 2.5, то это: +[RACSignal createSignal:])
Приведу два коротких примера и мы на этом закончим
Создадим простой сигнал:
Очевидно, что при создании подписки на данный сигнал, пока цикл не закончится, то мы не получим ни единого значения. У кого-то, код выполняющийся в этом блоке, будет довольно ресурсоемким. Попробуем разнести по тредам.
Создадим подписку на сигнал и укажем сигналу subscribeOn/deliverOn
В данном случае, как видно по комментариям, значения мы будем получать в главном потоке, где можно, к примеру, обновлять UI. А в блоке создании подписки код будет выполняться в другом потоке, что поможет снизить нагрузку на главный поток.
И последний пример, я покажу вам как из бэкграунд потока запустить код в главном потоке. С GCD это выглядело бы как все уже знают следующим образом:
И как это можно реализовать с RACSheduler: Как мы помним, при создании подписки на этот сигнал, мы указали, что он будет выполняться не в главном потоке. Но что делать, если в каком то месте, нам все понадобиться выполнить часть кода на главном потоке? Очень просто :) Здесь нам поможет - (RACDisposable *)schedule:(void (^)(void))block;
На этом все :) Спасибо большое за внимание! И кстати, отличная новость: Состоялся долгожданный релиз RAC4! https://github.com/ReactiveCocoa/ReactiveCocoa/releases/tag/v4.0.0