ReactiveCocoa use detailed 01
ReactiveCocoa (referred to as RAC) is an Github
open source functional reactive programming framework for iOS and OS development. It provides a series of APIs for combining and transforming value streams.
1. What is Responsive Turning into Thought?
Before learning a framework, you must first understand the programming idea of this framework. Before introducing the idea of reactive programming, let's first introduce the programming ideas that you have come into contact with before.
1. Object Oriented
- everything is an object
- It is a kind of programming language with objects as the basic program structure unit
- Typical object-oriented programming languages are
C++
,C#
,Java
etc.
2. Process Oriented
- A process-centric programming idea
- C is a procedural language
3. Chain programming idea
- It is to link multiple operations (multi-line code) together through a dot (.) to form a code, which makes the code more readable.
- Chain programming features: the return value of the method is block, the block must have a return value (the object itself), and block parameters (the value that needs to be manipulated)
- Typical framework: masonry framework.
4. Functional programming ideas
- everything is flow
- You don't need to consider the calling order, you just need to know the result
- Similar to the butterfly effect, generating an event will affect many things, these events will spread out like a stream, and then affect the result
- Representative: KVO application
5. Functional programming ideas
- It is to write the operation as a series of nested functions or method calls as much as possible
- Features: Each method must have a return value (its own object), take a function or block as a parameter, block parameter (value that needs to be operated) and block return value (operation result)
- Representative: ReactiveCocoa
6. ReactiveCocoa
Programming ideas
- functional programming
Functional Programming
- reactive programming
Reactive Programming
Therefore, ReactiveCocoa
described as a functional reactive programming (FRP) framework, RAC
some common classes are described below in detail
2. RACSiganl signal class
ReactiveCocoa
One of the most central concepts inRACStream
.RACStream
There are two subclasses -RACSignal
andRACSequence
; here we mainly talk aboutRACSignal
;- In
ReactiveCocoa
the entire library, itRACSignal
occupies a relatively important position, andRACSignal
the transformation operation is one of theRACStream
cores of the entire stream operation. - Let's take a look at
RACSignal
the complete process of being subscribed
- (void)test2 {
//创建信号
RACSignal *single = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送消息
[subscriber sendNext:@"a"];
[subscriber sendNext:@"b"];
//发送完成
[subscriber sendCompleted];
//清空数据
return [RACDisposable disposableWithBlock:^{
//当订阅者被消耗的时候就会执行
//当订阅者发送完成,或者error的时候也会执行
NSLog(@"RACDisposable的block");
}];
}];
//订阅信号
RACDisposable *disposable = [single subscribeNext:^(id _Nullable x) {
NSLog(@"value = %@", x);
} error:^(NSError * _Nullable error) {
NSLog(@"error: %@", error);
} completed:^{
NSLog(@"completed");
}];
//释放
[disposable dispose];
}
RACSignal
Some subclasses to look at before
RACDynamicSignal
: Dynamic signal, using ablock
to implement subscription behavior, we create an instance of this class when we useRACSignal
the+createSignal:
method ofRACEmptySignal
: empty signal,RACSignal
the+empty
method used to implement ;RACReturnSignal
: Unary signal,RACSignal
the+return:
method used to implement ;RACErrorSignal
: error signal,RACSignal
the+error:
method used to implement ;RACChannelTerminal
: Channel terminal,RACChannel
representing a terminal of , used to realize two-way binding
RACSignal
RACDynamicSignal
When creating a signal, the underlyingcreateSignal
method will be called, as follows:
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
The block here is a id<RACSubscriber>
type subscriber
, and this RACSubscriber
, we can click in to see some underlying implementations, the protocol methods are as follows:
@protocol RACSubscriber <NSObject>
@required
/// Sends the next value to subscribers.
- (void)sendNext:(nullable id)value;
/// Sends the error to subscribers.
- (void)sendError:(nullable NSError *)error;
/// Sends completed to subscribers.
- (void)sendCompleted;
/// Sends the subscriber a disposable that represents one of its subscriptions.
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
- The underlying implementation of RACSignal:
- 1. Create a signal, first
didSubscribe
save it to the signal, it will not trigger. - 2. When the signal is subscribed, it is
signal
calledsubscribeNext:nextBlock
- 2.1
subscribeNext
Subscribers will be created internallysubscriber
andnextBlock
saved tosubscriber
. - 2.2
subscribeNext
will be called internallysiganl的didSubscribe
- 2.3 When the signal subscription is completed and data is not sent, it is best to call the completed sending
[subscriber sendCompleted];
[RACDisposable disposable]
When the subscription is completed, the unsubscribe signal will be automatically called internally- 3.
siganl
ThedidSubscribe
middle call[subscriber sendNext:@1];
- 3.1 The
sendNext
bottom layer is actually executedsubscriber
nextBlock
- 1. Create a signal, first
3. Signal provider:RACSubject
- A signal provider, which can act as a signal and send a signal
- Subscribe first, then send signals
- Usage scenario: usually used instead of proxy/notification
1. RACSubject
Simple to use
- (void)setRacSubject1 {
//先订阅, 在发送信号
//1. 创建信号
RACSubject *subject = [RACSubject subject];
//2. 订阅
//内部创建RACSubscriber
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第一个订阅者--%@", x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第二个订阅者---%@", x);
}];
//3. 发送信号
//遍历所有的订阅者, 执行nextBlock
[subject sendNext:@2];
/** 打印结果
2018-03-17 20:18:19.782119+0800 ReactiveObjc[23883:1420936] 第一个订阅者--2
2018-03-17 20:18:19.784715+0800 ReactiveObjc[23883:1420936] 第二个订阅者---2
*/
}
- RACSubject: The underlying implementation is different from RACSignal
- 1. Call
subscribeNext
the subscription signal, just save the subscriber, and the subscriber'snextBlock
value has been assigned. - 2. Call
sendNext
the send signal, traverse all the subscribers just saved, and call the subscribers one by onenextBlock
- 1. Call
2. RACReplaySubject
Simple to use
- Repeatedly provide the signal class, a subclass of RACSubject
- Send the signal first, then subscribe to the signal;
- scenes to be used
-
- If a signal is subscribed once, it needs to send the previous value repeatedly, and use repeat to provide the signal class.
-
- The number can be set
capacity
to limitvalue
the number of caches, that is, only the latest values can be buffered
- The number can be set
-
- (void)setReplaySubject {
//创建信号
RACReplaySubject *replySub = [RACReplaySubject subject];
//发送信号
[replySub sendNext:@23];
[replySub sendNext:@34];
//订阅信号
// 遍历值,让一个订阅者去发送多个值
// 只要订阅一次,之前所有发送的值都能获取到.
[replySub subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
/**
2018-03-19 12:01:14.112253+0800 ReactiveObjc[5130:446958] 23
2018-03-19 12:01:14.112511+0800 ReactiveObjc[5130:446958] 34
*/
}
RACReplaySubject
The underlying implementation of
-
- When subscribing to a signal, the subscriber is saved internally, and the subscriber responds to the block
-
- When the signal is sent, it traverses the subscribers and calls the subscriber's nextBlock
-
- The sent signal will be saved. When the subscriber subscribes to the signal, the previously saved signal will act on the new subscriber one by one. The capacity of the saved signal is
capacity
determined, which is also different from RACSubject.
- The sent signal will be saved. When the subscriber subscribes to the signal, the previously saved signal will act on the new subscriber one by one. The capacity of the saved signal is
-
3. Alternative Agents/Notices
- Here we imagine a scenario of reverse value transfer, there is a custom view in vc, when clicked
View
, change the background color of vc - Usually what we do is to use proxy/notify/block
3-1. Let's take a look at the simple use of the proxy
Set protocol in custom View
#import <UIKit/UIKit.h>
@class SubjectView;
@protocol SubjectDelegate <NSObject>
@optional
- (void)viewWithTap:(SubjectView *)subView;
@end
@interface SubjectView : UIView
@property (nonatomic, weak) id<SubjectDelegate> delegate;
@end
In vc, follow the proxy, and implement the proxy method
/// 代理方法
-(void)viewWithTap:(SubjectView *)subView{
NSLog(@"完成代理, 点击了view");
UIColor *color = [UIColor colorWithRed:(arc4random() % 255) / 255.0 green:(arc4random() % 255) / 255.0 blue:(arc4random() % 255) / 255.0 alpha:1.0];
self.view.backgroundColor = color;
}
3-1. RACSubject
In lieu of proxy
in custom SubjectView.h
file
#import <UIKit/UIKit.h>
#import <ReactiveObjC.h>
@interface SubjectView : UIView
@property (nonatomic, strong) RACSubject *subject;
@end
in custom SubjectView.m
file
#import "SubjectView.h"
@implementation SubjectView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//发送信号
[_subject sendNext:self];
}
@end
Let's take a look at the operation in vc
- (void)setupSubjectView {
SubjectView *subV = [[SubjectView alloc]init];
subV.backgroundColor = [UIColor redColor];
subV.frame = CGRectMake(100, 100, 100, 100);
RACSubject *subject = [RACSubject subject];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"完成代理, 点击了view");
UIColor *color = [UIColor colorWithRed:(arc4random() % 255) / 255.0 green:(arc4random() % 255) / 255.0 blue:(arc4random() % 255) / 255.0 alpha:1.0];
self.view.backgroundColor = color;
}];
subV.subject = subject;
[self.view addSubview:subV];
}
- The knowledge points related to ReactiveObjc will be continuously updated later…
- Recommended article: iOS ReactiveCocoa most commonly used API finishing