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];
}];
}
如下圖
demo 整理完會一并上傳;
-
附上關于 RACSignal的思維導圖方便大家理解(還未完成)
RAC框架各種組件.png