RACSignal

RACSignal類

他的基類是RACStream,一般表示將來有數據傳遞,只要有數據改變,信號內部接收到數據,就會馬上發出數據。

  • 信號類(RACSiganl),只是表示當數據改變時,信號內部會發出數據,它本身不具備發送信號的能力,而是交給內部一個訂閱者去發出

  • 默認一個信號都是冷信號,也就是值改變了,也不會觸發,只有訂閱了這個信號,這個信號才會變為熱信號,值改變了才會觸發

  • 如何訂閱信號:調用信號RACSignal的subscribeNext就能訂閱

具體執行流程

使用三部曲,

1.創建信號
2.訂閱信號
3.發送信息

  • 創建和發送
-(void)CreateSignal
{
//三步 創建 訂閱 發送
self.signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//這個block什么時候調用呢?,在我們訂閱信號的時候調用
NSLog(@"創建signal-----");
//發送信息
[subscriber sendNext:@"這是一個實驗"];
// 如果不在發送數據,最好發送信號完成,內部會自動調用[RACDisposable disposable]取消訂閱信號。
[subscriber sendCompleted];
NSLog(@"什么時間運行");
return [RACDisposable disposableWithBlock:^{
// block調用時刻:當信號發送完成或者發送錯誤,就會自動執行這個block,取消訂閱信號。
// 執行完 Block后,當前信號就不在被訂閱了。
NSLog(@"信號被銷毀");
}];
}];
}

RACDisposable:用于取消訂閱或者清理資源,當信號發送完成或者發送錯誤的時候,就會自動觸發它。比如:不想監聽某個信號時,可以通過它主動取消訂閱信號

RACSubject:RACSubject:信號提供者,自己可以充當信號,又能發送信號。通常用來代替代理,有了它,就不必要定義代理了。

  • 訂閱
#
pragma mark ---- 訂閱信號
- (IBAction)Subscription:(id)sender {

//方法一
// [self.signal subscribeNext:^(id _Nullable x) {
//
// NSLog(@"訂閱信號-----%@",x);
// }];

//方法二
[self.signal subscribeNext:^(id _Nullable x) {
//接收到正常發送的信號,并打印信號傳過來的信息
NSLog(@"訂閱信號-----%@",x);

} error:^(NSError * _Nullable error) {
//接收到錯誤的信號,并打印出錯誤信息
NSLog(@"%@",error);

} completed:^{
//接收到完成信號, 并打印出完成信息,若為錯誤信號則不打印
NSLog(@"完成");

}];

}
運行結果:
2018-03-26 12:31:32.054986+0800 RACSignal[92861:4461509] 創建signal-----
2018-03-26 12:31:32.055229+0800 RACSignal[92861:4461509] 發送的信息是-----這是一個實驗
2018-03-26 12:31:32.055507+0800 RACSignal[92861:4461509] 完成
2018-03-26 12:31:32.055722+0800 RACSignal[92861:4461509] 什么時間運行

RACSubscriber:表示訂閱者的意思,用于發送信號,這是一個協議,不是一個類,只要遵守這個協議,并且實現方法才能成為訂閱者。通過create創建的信號,都有一個訂閱者,幫助他發送數據。

  • 從上面的demo 中可以看出Signal 的執行循序如下圖


    RACSignal_Flowchart.png

即創建signal的 block 在訂閱之后 調用,訂閱的block 在發送完數據之后調用

循環引用的問題

RAC在使用的時候由于系統提供的信號是始終存在的,所以在block中使用屬性或者成員變量幾乎都會涉及到一個循環引用的問題,有兩種方法可以解決,使用weakself解決或者RAC提供的weak-strong dance.用法也比較簡單:在 block 的外部使用 @weakify(self),在 block 的內部使用 @strongify(self),具體的方法如下:

#pragma mark ---- 如何解決循環引用
-(void)RetainCiteBtn
{
//@-----解決循環引用------
@weakify(self);
[[self.RetainCite rac_signalForControlEvents:UIControlEventTouchUpInside] 
subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self);
NSLog(@"解決循環引用問題%@",self.view);
}];
}

簡單應用

1,實現對 textField輸入內容的實時監聽

@property (weak, nonatomic) IBOutlet UITextField *name_TF;

#pragma mark ---- textField輸入內容的實時監聽
-(void)name_tfSignal
{
[[self.name_TF rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
}
監聽文本框文字改變:rac_textSignal:只要文本框發出改變就會發出這個信號

2.想將兩個信號或者多個整合成一個信號

-(void)nameWithpwSignal{
 [[RACSignal combineLatest:@[self.name_TF.rac_textSignal,self.pw_TF.rac_textSignal]] 
subscribeNext:^(RACTuple * _Nullable x) 
{
 NSString * name = x.first; NSString * pwd = x.second; 
 NSLog(@"name:%@,age:%@",name,pwd); 
}];
}
關于合并信號的幾個方法,combineLatest: zip Sample, 在后續的 demo 中會有體現

3.判斷登錄按鈕是否能點擊

-(void)isEventforLogin
{
//根據texfile的內容覺得按鈕是否可以點擊
@weakify(self);
[[RACSignal combineLatest:@[self.name_TF.rac_textSignal,self.pw_TF.rac_textSignal] 
reduce:^id(NSString * name , NSString * pw){

return @(name.length>0&&pw.length>0);

}]subscribeNext:^(id _Nullable x) {
@strongify(self);
self.Login.enabled = [x boolValue];

}];
}

4.UI綁定 輸入框輸入實施改變model 的值, model值改變通知label顯示改動后的信息

-(void)UIChangAndModel
{
self.model = [[RACSignalModel alloc]init];


//UI綁定模型
self.model.name = @"初始化";
// self.model.age = 0;
//雙向綁定
//RACChannelTo(self.ChageValue, text) =RACChannelTo(self.model, name); 等同下句話
RAC(self.ChageValue,text) = RACObserve(self.model, name);
/*
RAC(self.ChageAge,text) = RACObserve(model, age);
這句話程序崩潰,信息 reason: '-[__NSCFNumber rangeOfCharacterFromSet:]: unrecognized selector sent to instance 0xb000000000000003'原因如下
這里不能使用基本數據類型,RAC中傳遞的都是id類型,使用基本類型會崩潰,所以使用map方法對返回值進行了更替如下:
*/
RAC(self.ChangeAgeLabel,text)= [RACObserve(self.model, age) map:^id(id value) {
return [value description];
}];

[[RACSignal combineLatest:@[self.ChangModel.rac_textSignal,self.ChageAge.rac_textSignal]] subscribeNext:^(RACTuple * x) {
self.model.name = x.first;
self.model.age = [x.second intValue];
}];

}

如下圖


Snip20180327_14.png

demo 整理完會一并上傳;

  • 附上關于 RACSignal的思維導圖方便大家理解(還未完成)


    RAC框架各種組件.png
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 昨天開學就進行了考試,學生不在狀態,考的也不好,小鵬的分數尤其低,不過我沒有生氣,可是今天上課效果不太好,我就免不...
    薇薇_24ee閱讀 235評論 0 1
  • 中午秋日的陽光灑落在地板上,明亮而愉快。 這個時節是發自內心地喜愛。微涼的秋風與和煦的陽光組合在一...
    土豆是只貓閱讀 313評論 2 8