ReactiveCocoa. Concurrency. Multithreading
Today I would like to talk about working with threads in ReactiveCocoa. I will not go into the details of the framework and I believe that you are already familiar with the basic principles of reactive programming in iOS. 
Working with streams in a mobile application is the most important topic and everyone knows this. The standard tools for this are GCD or NSOperation. But when using ReactiveCocoa in our project, everything becomes a little different. No, nobody forbids you to use standard tools, but why? Will we shove a GCD into each block? To do this, ReactiveCocoa came up with a very convenient implementation.
For work with multithreading in ReactiveCocoa there is a class RACScheduler. In essence, this is a wrapper over GCD ... and has the same thread priorities as GCD:
Consider the main RACScheduler methods that we may need when working with it:
From the name, in principle, it becomes clear that we are returned to the RACScheduler, which will do the work in the main thread.
In this case, the RACSCheduler with the specified priority is returned to us and is no longer in the main thread.
Returns a RACScheduler with a priority of RACSchedulerPriorityDefault.
Returns the current RACScheduler from the current NSThread.
A block that the RACSheduler can execute anywhere. And we will return to this.
The following are the basic functions for RACSignal that we can use to control multithreading:
This RACSignal method says that the blocks for obtaining new values are in subscribeNext / doNext / subscribeError / etc. will be executed in the RACSCheduler that we will refund.
This RACSignal method says in which RACScheduler the block created when creating the subscription will be executed (if we are talking about ReactiveCocoa 2.5, then this: + [RACSignal createSignal:])
I’ll give you two short examples and we will end here.
Create a simple signal:
Obviously, when creating a subscription to this signal, until the cycle ends, we will not get a single value. For someone, the code running in this block will be quite resource intensive. Let's try to spread by threads.
Create a signal subscription and point to the signal subscribeOn / deliverOn
In this case, as can be seen from the comments, we will get the values in the main thread, where, for example, we can update the UI. And in the block for creating a subscription, the code will be executed in another thread, which will help reduce the load on the main thread.
And the last example, I will show you how to run code from the background stream in the main stream.
With a GCD, it would look like everyone already knows as follows:
And how can this be implemented with RACScheduler:
As we recall, when creating a subscription to this signal, we indicated that it would not be executed in the main thread. But what if, in some place, we all need to execute part of the code on the main thread? Very simple :) Here it will help us - (RACDisposable *) schedule: (void (^) (void)) block;
Working with streams in a mobile application is the most important topic and everyone knows this. The standard tools for this are GCD or NSOperation. But when using ReactiveCocoa in our project, everything becomes a little different. No, nobody forbids you to use standard tools, but why? Will we shove a GCD into each block? To do this, ReactiveCocoa came up with a very convenient implementation.
For work with multithreading in ReactiveCocoa there is a class RACScheduler. In essence, this is a wrapper over GCD ... and has the same thread priorities as GCD:
typedef enum : long {
	RACSchedulerPriorityHigh = DISPATCH_QUEUE_PRIORITY_HIGH,
	RACSchedulerPriorityDefault = DISPATCH_QUEUE_PRIORITY_DEFAULT,
	RACSchedulerPriorityLow = DISPATCH_QUEUE_PRIORITY_LOW,
	RACSchedulerPriorityBackground = DISPATCH_QUEUE_PRIORITY_BACKGROUND,
} RACSchedulerPriority;
Consider the main RACScheduler methods that we may need when working with it:
From the name, in principle, it becomes clear that we are returned to the RACScheduler, which will do the work in the main thread.
+ (RACScheduler *)mainThreadScheduler;
In this case, the RACSCheduler with the specified priority is returned to us and is no longer in the main thread.
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority;
Returns a RACScheduler with a priority of RACSchedulerPriorityDefault.
+ (RACScheduler *)scheduler;
Returns the current RACScheduler from the current NSThread.
+ (RACScheduler *)currentScheduler;
A block that the RACSheduler can execute anywhere. And we will return to this.
- (RACDisposable *)schedule:(void (^)(void))block;
The following are the basic functions for RACSignal that we can use to control multithreading:
This RACSignal method says that the blocks for obtaining new values are in subscribeNext / doNext / subscribeError / etc. will be executed in the RACSCheduler that we will refund.
- (RACSignal *)deliverOn:(RACScheduler *)scheduler
This RACSignal method says in which RACScheduler the block created when creating the subscription will be executed (if we are talking about ReactiveCocoa 2.5, then this: + [RACSignal createSignal:])
- (RACSignal *)subscribeOn:(RACScheduler *)scheduler
I’ll give you two short examples and we will end here.
Create a simple signal:
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id  subscriber) {
// block executes on other thread with default priority
        for (NSInteger i = 0; i < 5000; i++) {
            NSLog(@"LOL");
            if (i == 5000) {
            [subscriber sendNext:@(YES)];
            }
        }
        return nil;
    }];
 Obviously, when creating a subscription to this signal, until the cycle ends, we will not get a single value. For someone, the code running in this block will be quite resource intensive. Let's try to spread by threads.
Create a signal subscription and point to the signal subscribeOn / deliverOn
[[[signal subscribeOn:[RACScheduler scheduler]]
                deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
                // block executes on main thread
}];
In this case, as can be seen from the comments, we will get the values in the main thread, where, for example, we can update the UI. And in the block for creating a subscription, the code will be executed in another thread, which will help reduce the load on the main thread.
And the last example, I will show you how to run code from the background stream in the main stream.
With a GCD, it would look like everyone already knows as follows:
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
        // do something
        dispatch_async(dispatch_get_main_queue(), ^{
            // do something
        });
    });
And how can this be implemented with RACScheduler:
As we recall, when creating a subscription to this signal, we indicated that it would not be executed in the main thread. But what if, in some place, we all need to execute part of the code on the main thread? Very simple :) Here it will help us - (RACDisposable *) schedule: (void (^) (void)) block;
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id  subscriber) {
// block executes on other thread with default priority
        for (NSInteger i = 0; i < 5000; i++) {
            NSLog(@"LOL");
            if (i == 5000) {
            [subscriber sendNext:@(YES)];
            }
        }
        [[RACScheduler mainThreadScheduler] schedule:^(void v) {
            // do something on main thread
        }];
        return nil;
    }];