ReactiveCocoa(簡稱爲RAC),是由Github
開源的一個應用於iOS和OS開發的函數式響應式編程框架,它提供了一系列用來組合和轉換值流的 APIhtml
學習一個框架以前, 首先要了解這個框架的編程思想, 這裏在介紹響應式編程思想以前, 先介紹一下以前接觸過的編程思想ios
C++
, C#
, Java
等ReactiveCocoa
編程思想Functional Programming
Reactive Programming
因此, ReactiveCocoa
被描述爲函數響應式編程(FRP)框架, 下面具體介紹一下RAC
的一些常見類git
ReactiveCocoa
中最核心的概念之一就是信號RACStream
。RACStream
中有兩個子類——RACSignal
和 RACSequence
; 這裏咱們就主要說一下RACSignal
;ReactiveCocoa
整個庫中,RACSignal
佔據着比較重要的位置,而RACSignal
的變換操做更是整個RACStream
流操做核心之一RACSignal
被訂閱的完整過程- (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
的一些子類
RACDynamicSignal
: 動態信號,使用一個 block
來實現訂閱行爲,咱們在使用 RACSignal
的 +createSignal:
方法時建立的就是該類的實例RACEmptySignal
:空信號,用來實現 RACSignal
的 +empty
方法;RACReturnSignal
:一元信號,用來實現 RACSignal
的 +return:
方法;RACErrorSignal
:錯誤信號,用來實現 RACSignal
的 +error:
方法;RACChannelTerminal
:通道終端,表明 RACChannel
的一個終端,用來實現雙向綁定
RACSignal
在建立信號的時候,底層會調用RACDynamicSignal
的createSignal
的方法, 以下:github
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
複製代碼
這裏的block是一個 id<RACSubscriber>
類型的subscriber
, 而這個RACSubscriber
, 咱們能夠點進去看一些底層實現, 協議方法以下:編程
@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;
複製代碼
didSubscribe
保存到信號中,還不會觸發。signal
的subscribeNext:nextBlock
subscribeNext
內部會建立訂閱者subscriber
,而且把nextBlock
保存到subscriber
中。subscribeNext
內部會調用siganl的didSubscribe
[subscriber sendCompleted];
[RACDisposable disposable]
取消訂閱信號siganl
的didSubscribe
中調用[subscriber sendNext:@1];
sendNext
底層其實就是執行subscriber
的nextBlock
RACSubject
RACSubject
簡單使用- (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 */
}
複製代碼
subscribeNext
訂閱信號,只是把訂閱者保存起來,而且訂閱者的nextBlock
已經賦值了。sendNext
發送信號,遍歷剛剛保存的全部訂閱者,一個一個調用訂閱者的nextBlock
RACReplaySubject
簡單使用capacity
數量來限制緩存的value
的數量,即只緩充最新的幾個值- (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
的底層實現
capacity
決定,這也是有別於RACSubject的View
的時候, 更換vc的背景顏色在自定義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
複製代碼
在vc中, 遵循代理, 並實現代理方法框架
/// 代理方法
-(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;
}
複製代碼
RACSubject
代替代理在自定義SubjectView.h
文件中dom
#import <UIKit/UIKit.h>
#import <ReactiveObjC.h>
@interface SubjectView : UIView
@property (nonatomic, strong) RACSubject *subject;
@end
複製代碼
在自定義SubjectView.m
文件中編程語言
#import "SubjectView.h"
@implementation SubjectView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//發送信號
[_subject sendNext:self];
}
@end
複製代碼
下面看一下在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];
}
複製代碼