The first RAC

RAC – ReactiveCocoa, GitHub is an open source framework, is a set of functional response programming framework

So what is the use of this framework?

One of the most important classes in RAC is called RACsignal, when we have data, we create a signal, so it may be too abstract

RACSignal in the creation of the object, not the alloc, init method, but to provide us with a class method:

(RACSignal *) createSignal: (RACDisposable * (^) (id< RACSubscriber> subscriber)) didSubscribe

In this method, a parameter didSubscribe, which is a block, this block is a parameter of type ID object, comply with the RACSubscriber agreement, the return value is of type RACDisposable * block.

The first RAC
create signal times wrong

The twenty-eighth line error, it is because your block is with a return value of block, while you and what did not return, so regardless of the consequence, to return to a nil. and then I do something in block, print a word, the code is as follows:

- (void) viewDidLoad [super RACSignal *signal {viewDidLoad]; [RACSignal = createSignal:^RACDisposable * _Nullable (id< RACSubscriber> _Nonnull; subscriber) {NSLog (@ signal has been created "); return nil;}];}
The code is written here, the code in this block will execute? Obviously not, then, when the code to execute it?

This time the need for signal subscription:
– (RACDisposable *) subscribeNext: (void (^) (ID) (x))

This code, and a block parameter, the block is a parameter for objects of type ID, the return value is the empty block signal, when the subscription in this block is what I do, the above printing is also able to perform:

The first RAC
execution block

Let’s take a look at how this is implemented:

+ (RACSignal *) createSignal: (RACDisposable * (^) (id< RACSubscriber> subscriber)) didSubscribe {return [RACDynamicSignal};}
+ (RACSignal * createSignal:) (RACDisposable (* ^) (id< RACSubscriber> subscriber)) {RACDynamicSignal *signal = [[self didSubscribe alloc] init]; signal-> _didSubscribe = [didSubscribe copy]; return [signal @ setNameWithFormat: "+createSignal:"];}

Where signal-> _didSubscribe = [didSubscribe copy]; this code will didSubscribe this block is stored in the object’s properties

That we are not in – (RACDisposable *) subscribeNext: (void (^) (ID)) nextBlock this method called block:

- (RACDisposable) subscribeNext: (void (^) (ID x nextBlock)) {NSCParameterAssert (nextBlock! = NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL]; return [self subscribe:o];}

In the subscribe method, the didSubscribe method is called

The first RAC
caller is RACDynamicSignal
The first RAC
didSubscribe implementation of this block

From the above we can see that the didSubscribe block in the signal when the subscription is called, the call at the same time, the subscriber parameter to block, so we

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable (id< RACSubscriber> _Nonnull; subscriber) {NSLog (@ signal has been created "); [subscriber sendNext:@" subscriber send "]; return nil;}];

This code block inside is to get the subscriber object, and then I call the sendNext this method, what will happen?

The first RAC
sendNext trigger block call

We show that the subscribeNext: method parameter block is called

So let’s look at what sendNext does inside

The first RAC
execution nextBlock

This method implements the block that I saved in the subscriber property, and the value parameter is passed to the nextBlock, so when the nextBlock executes, you can get the X parameter

The first RAC
block code block implementation details
The first RAC
holds the block code block in the property

Well, we have no attention + (RACSignal * createSignal:) (RACDisposable (* ^) (id< RACSubscriber> subscriber)) return block parameters of didSubscribe this method is the value of doing, then we give the block a return value:

Return value of The first RAC

It is seen that the return value is of type RACDisposable, and then we create a RACDisposable object with + (instancetype) disposableWithBlock: (void (^) (void)) the block class method, the same parameter is a block, but the block was soon called, why is this?

The first RAC
subscriber life cycle ends

This return value

RACDisposable *disposable = [RACDisposable disposableWithBlock:^{NSLog (@ disposable);}]; return disposable;

When the subscribeNext: method is called, the disposable property of the subscriber is assigned to the subscriber attribute (which can be understood in the first place)

- (void) dealloc {[self.disposable dispose];}

This time

RACDisposable *disposable = [RACDisposable disposableWithBlock:^{NSLog (@ disposable);}]; return disposable;

The print in this code will be executed

However, when the subscriber is strongly referenced, the dealloc method is not called and the disposable is not called.

The first RAC
strong reference subscriber, disposable will not be called

If subscriber is a strong reference, I want to cancel the subscription should be how to do?
subscribeNext: this method is to return a value, the return value is above the return value of didSubscribeblock (can be so understanding)
I use a variable to receive, and then manually disposable:

The first RAC
manual disposable

So what does RACDisposable do?

This class can help us cancel the subscription, cancel the subscription when the signal is finished or fail, and call the specified code
In RAC, there is a class is very important, but also very special, called RACSubject, this class can create a signal, you can also send a signal:
RACSubject *subject = [RACSubject subject]; [subject subscribeNext:^ (ID _Nullable x) {NSLog ("subject has been subscribed% @ @", x);}]; [subject sendNext:@ subject has been sended "];
  • When creating a signal: this framework overrides the init method:
(instancetype) + subject [[self alloc] {return init];} - (instancetype init) {self = [super init]; if (self = = Nil) return = nil; _disposable [RACCompoundDisposable compoundDisposable]; _subscribers = [[NSMutableArray alloc] initWithCapacity:1]; return self;}
  • He created a mutable array that is used to add subscriber
- (RACDisposable) subscribe: (id< RACSubscriber> subscriber) {NSCParameterAssert (subscriber! = Nil); RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable] NSMutableArray; *subscribers = self.subscribers; @synchronized (subscribers) {[subscribers addObject:subscriber];} [disposable addDisposable:[RACDisposable disposableWithBlock:^{@synchronized (subscribers) Since newer subscribers are generally {/ / shorter-lived, search starting from the end of the / list. NSUInteger index = [subscribers indexOfObjectWithOptions NSEnumerationReverse passingTest:^ BOOL (id< RACSubscriber> obj, NSUInteger index, BOOL *stop) {return obj = = subscriber;}]; if (index! = NSNotFound) [subscribers removeObjectAtIndex:index]; return disposable;}}}]];
  • Then when the signal is sent, it will traverse the array, the inside of the subscriber out one by one, sending signals:
The first RAC
subject transmit signal
So, the benefits of using RACSubject is that you can subscribe to a number of signals, and finally send a signal to call together
The first RAC
subscribe to multiple signals
Now sum up RACSignal and RACSubject
The first RAC

The essence of RACSubject is actually the same as RACSignal, so why is it possible to create a signal and subscribe to a signal?

In OC, there is no concept of multiple inheritance, in order to achieve the effect of multiple inheritance, you can first inherit a class, and then to achieve one or more protocols, so as to achieve the effect of multiple inheritance
The first RAC
“multiple inheritance”

So, say so much, what is the use of this RAC?

Use big, because it can achieve KVO, proxy, notification, block function, set a variety of functions in one, when you use the RAC, you can use RAC to achieve the above design patterns can be achieved

For example, now has a simple demand: a custom
view with a button, click on the button after the button background color transferred to the controller of the view. which is a typical value of reverse transfer, notice, agent, block can be used. How to do that with RAC?

  • The first is to create a signal, where the signal needs to be created, where the value is passed, where the signal is created, with a lazy loading to create subject objects:
- (RACSubject *) subject {if ((_subject) {_subject = [RACSubject subject];} return};})
  • And then when the button hits the color signal:
- (IBAction) buttonClick: (UIButton *) sender {[self.subject sendNext:sender.backgroundColor];}
  • Finally, the value of where to go, where the subscription signal:
- (void) viewDidLoad [self.yfView.subject subscribeNext:^ {[super viewDidLoad]; (ID _Nullable x) {self.view.backgroundColor = x;}]};

So simple a few steps to complete the demand, very simple and convenient, the effect is as follows:

The first RAC
implementation effect
Well, now look at another important class, called RACReplaySubject
The first RAC
RACReplaySubject is inherited from RACSubject

RACReplaySubject is inherited from RACSubject’s

The first RAC
valid code

So the block in the subscription signal can be executed. So what’s the difference between this class and RACSubject?

The first RAC
also valid code

When we exchange the subscription signal and send the signal to the location and found that the subscription of block can still be executed, which is different from RACSubject, but why is this?

This is only the initial RAC, I also started learning from 0, there is a wrong place, but also please criticize me, together

First look at the creation of the RACReplaySubject object, what is different

The first RAC
create variable array

It can be seen that this class overrides the init method and creates an array named valuesRecieved

Then, in the process of sending signals:

The first RAC
array to save the send signal

When the transmitted signal, the valuesReceived array just created the need to send the signal stored in the array. Stored in the array and why?:

The first RAC
really subscribe to the signal
The first RAC
subscription signal specific implementation

Can be seen from the figure, when the subscription signal, will save valuesReceived in the array signal Lai Yibo traversal, then take them out and send yourself out. So, even if the first signal sent in a subscription signal, it can be done, because the internal subscription signal also sent a signal.