RAC響應(yīng)式編程---iOS筆記摘錄

目錄

前言

RAC(ReactiveCocoa) 
    函數(shù)式編程彭沼、響應(yīng)式編程    
    Github上的開源框架

響應(yīng)式編程,是一種通用的編程范式,提高了開發(fā)效率脖旱。
我的理解就是:監(jiān)聽事件,然后在事件發(fā)生后做相應(yīng)回調(diào)處理币旧。
/**
delegate践险、通知、block
KVO
*/
在命令式編程環(huán)境中吹菱,a=b+c表示將表達(dá)式的結(jié)果賦給a巍虫,而之后改變b或c的值不會影響a。
但在響應(yīng)式編程中鳍刷,可以做到a的值隨b或c的更新而更新占遥。
RAC框架圖

1. 使用

引入(集成ReactiveCocoa框架)
    pod 'ReactiveObjC'
    #import <ReactiveObjC/ReactiveObjC.h>
  1. 常用
添加監(jiān)聽事件
    // 給UITextFiled添加值改變事件
    [[[UITextField new]rac_signalForControlEvents:UIControlEventEditingChanged]subscribeNext:^(id x) {
        //
    }];
    等同于(簡化版)
    [[[UITextField new]rac_textSignal]subscribeNext:^(NSString * _Nullable x) {
        // UIControlEventEditingChanged
    }];

    // 給按鈕添加點擊事件
    [[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
添加手勢
    [[UIButton new]addGestureRecognizer:({
        UITapGestureRecognizer *tapG=[UITapGestureRecognizer new];
        [[tapG rac_gestureSignal]subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        }];
        tapG;
    })];
調(diào)用方法
    @weakify(self)
    [[self rac_signalForSelector:@selector(viewDidLoad)]subscribeNext:^(id x) {
        @strongify(self)
        //
    } error:^(NSError * _Nullable error) {
    } completed:^{
    }];
dele代理
    UIAlertView *alertV=[[UIAlertView alloc]initWithTitle:@"alert" message:@"content" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"sure", nil];
    // 實現(xiàn)代理方法clickedButtonAtIndex 來自協(xié)議UIAlertViewDelegate
    [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]subscribeNext:^(id  _Nullable x) {
    }];
    // 等同于(簡化版)
    [[alertV rac_buttonClickedSignal]subscribeNext:^(NSNumber * _Nullable x) {
    }];
    [alertV show];
NSNotificationCenter通知
    添加觀察者
    [[[NSNotificationCenter defaultCenter]rac_addObserverForName:@"notiName" object:nil]subscribeNext:^(NSNotification * _Nullable noti) {
        // noti.name noti.object noti.object
    }];
    發(fā)送通知
    [[NSNotificationCenter defaultCenter]postNotificationName:@"notiName" object:@[@"1",@"2"]];
KVO鍵值觀察
    // 方式一
    [RACObserve([UIScrollView new], contentOffset) subscribeNext:^(id  _Nullable x) {
    }];
    // 方式二
    [[self rac_valueForKeyPath:@"age" observer:nil] subscribeNext:^(id x ){
        NSLog(@"%@",x);
    }];
RACSubject
    // 用于view中不同button的點擊事件
    RACSubject *subj=[RACSubject subject];
    [subj sendNext:@(100)];
    // 外部調(diào)用
    [subj subscribeNext:^(NSNumber *tag) {
    }];
    
cell.clickSubject 
    @weakify(self);
    [[cell.clickSubject takeUntil:cell.rac_prepareForReuseSignal] subscribeNext:^(NSNumber *x) {
        @strongify(self);
        [self clickCellBtn:[x intValue] atIndex:indexPath];
    }];
值綁定

RAC(self.label.text) = _textField.rac_textSignal;
RAC(_personVM,mobile)=_phoneTF.rac_textSignal;
  1. 接口命令(用于MVVM)
+(RACSignal *)PostWithURL:(NSString *)urlStr parameters:(NSDictionary *)paramDic animated:(BOOL)animated{
    return [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
            [YTNetworkTool POST:urlStr parameters:paramDic SuccessBlock:^(BOOL isOK, NSDictionary *dic) {
                // 回調(diào)
                [subscriber sendNext:dic];
                [subscriber sendCompleted];
            } failBlock:^(NSError *error) {
                [subscriber sendError:error];
            } animated:animated];
    
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"信號發(fā)送完成或發(fā)送錯誤后調(diào)用,會自動執(zhí)行這個block,并取消訂閱信號");
        }];
    }]replayLazily];
}
    _addRouteCommand=[[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        //
        NSDictionary *paramDic=@{@"isOpen":self.isOpen};
        return [YTServiceObject PostWithURL:API_AddRouteT parameters:paramDic animated:true];
    }];
    執(zhí)行命令(調(diào)用接口)
    vm.isOpen=@(true);
    [[vm.addRouteCommand execute:nil] subscribeNext:^(NSDictionary *dic) { 
      // dic
    }];
    [[[vm.addRouteCommand execute:nil]deliverOnMainThread] subscribeNext:^(NSDictionary *dic) { 
      // dic
    }];

    // 命令在執(zhí)行中(用于加載 加載中...)
    [[vm.addRouteCommand executing]subscribeNext:^(NSNumber * _Nullable x) {
        if(x.boolValue){
            // 加載 加載中...
        }else{
            // 隱藏 加載中...
        }
    }];

兩個信號都收到時回調(diào)

RACSignal*signalA = [RACSignal createSignal:^RACDisposable *(id <RACSubscribe>subscriber){
  NSLog(@"數(shù)據(jù)請求1");
[subscriber sendNext:@"數(shù)據(jù)請求1請求下來的數(shù)據(jù)"];
return nil;
}];
RACSignal*signalB = [RACSignal createSignal:^RACDisposable *(id <RACSubscribe>subscriber){
  NSLog(@"數(shù)據(jù)請求2");
[subscriber sendNext:@"數(shù)據(jù)請求2請求下來的數(shù)據(jù)"];
return nil;
}];
[self rac_liftSelector:@Selector(updateUI) withSignalFromArray:@[signalA,signalB]];
 //將 textfield 輸入信號的 返回值進(jìn)行修改  得到新的信號倾剿!
    RACSignal *firstSignal = [self.firstTextfield.rac_textSignal map:^id(NSString *firstString) {
        if (firstString.length >= 5 && firstString.length <= 10) {
            return @(YES);
        }
        return @(NO);
    }];
     RACSignal *secondSignal = [self.secondTextfield.rac_textSignal map:^id(NSString *secondString) {
         if (secondString.length >5 && secondString.length < 10) {
             return @(YES);
         }
         return @(NO);
     }];
    // 綁定用戶名筷频、密碼判斷結(jié)果的2個信號量,如果都為真前痘,則按鈕可用
    RAC(self.loginButton,enabled) = [RACSignal combineLatest:@[firstSignal,secondSignal] reduce:^(NSNumber *firstRes,NSNumber *secondRes){
        return @(firstRes.boolValue && secondRes.boolValue);
    }];
  1. 信號加條件
map 映射(攔截做額外處理)

    [[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside]map:^id(id value) {
        NSLog(@"value: %@",value);
        return @"hello";
    }]subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
filter 過濾(攔截不符合情況)

    // 監(jiān)聽文本框的輸入,而且只有大于3個長度的時候才會打印
    [[self.textField.rac_textSignal filter:^BOOL(id value) {
        return [value length] > 3;
    }]subscribeNext:^(id x) {
        NSLog(@"x:%@",x);
    }];
延時

[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
}];

[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
}];

take:2   選取前兩個信號
skip:2   跳過前兩個信號
repeat   無限重復(fù)執(zhí)行
delay:3  延遲3s發(fā)送信號
throttle:0.5           0.5s內(nèi)信號不發(fā)生變化則觸發(fā)
distinctUntilChanged   不會連續(xù)發(fā)送兩次相同的信號
timeout:2       超時2s后觸發(fā)error
ignore:@"1"     忽略信號1


[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        [self.textField endEditing:YES];
        //        [alertView show];
      
        // 創(chuàng)建信號
        RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"1"];
            [subscriber sendNext:@"2"];
            [subscriber sendNext:@"3"];
            [subscriber sendNext:@"4"];
            [subscriber sendCompleted];
            return nil;
        }] take:2];  // skip:2凛捏、repeat
        
        // 發(fā)送信號
        [signal subscribeNext:^(id x) {
            NSLog(@"x : %@",x);
        } completed:^{
            NSLog(@"completed");
        }];
    }];
將多個不同類型的數(shù)據(jù)組合成一個元組
    // 把參數(shù)中的數(shù)據(jù)包裝成元組
    RACTuple *tuple = RACTuplePack(@"xmg",@20,@"m",@(999),@[@"a"],@{@"key":@"value"});
    
    RACTupleUnpack(NSString *name,NSNumber *age,NSString *sex,NSNumber *price,NSArray *arr,NSDictionary *dic) = tuple;
    NSLog(@"name:%@  age:%@  sex:%@  price:%@ arr:%@  dic:%@",name,age,sex,price,arr,dic);

遍歷數(shù)組、字典

    NSArray *contentArr=@[@"hello",@"world",@"!"];
    [contentArr.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
    }];

    NSDictionary *paramDic=@{@"hello":@"world"};
    [paramDic.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        RACTwoTuple *tuple=(RACTwoTuple *)x;
        // key: tuple[0]
        // value: tuple[1]
    }];
  1. 基礎(chǔ)
信號RACSignal
    // 1. 創(chuàng)建信號
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3. 發(fā)送信號
        [subscriber sendNext:@"唱歌"];
        // 調(diào)用該方法銷毀信號芹缔,否則該信號一直占用著內(nèi)存
        [subscriber sendCompleted];
        // 3.1 發(fā)送error信號
        [subscriber sendError:[NSError errorWithDomain:NSURLErrorDomain code:1001 userInfo:@{@"error":@"error message"}]];
        // 4. 銷毀信號完畢后回調(diào)
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"singal已銷毀");
        }];
    }];
    // 2. 訂閱信號
    RACDisposable *disposable = [signalA subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    // 取消訂閱
    // [disposable dispose];
    // 2.1 訂閱error信號
    [signalA subscribeError:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];


信號動作:
  信號映射:map坯癣、flattenMap
  信號過濾:filter、ignore最欠、distinctUntilChanged
  信號合并:combineLatest示罗、reduce、merge芝硬、zipWith
  信號連接:concat蚜点、then
  信號操作時間:timeout、interval拌阴、dely
  信號跳過:skip
  信號取值:take绍绘、takeLast、takeUntil
  信號發(fā)送順序:donext、cocompleted
  獲取信號中的信號:switchToLatest
  信號錯誤重試:retry
避免循環(huán)引用
  @weakify(self)
  @strongify(self)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陪拘,一起剝皮案震驚了整個濱河市厂镇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌左刽,老刑警劉巖捺信,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欠痴,居然都是意外死亡迄靠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門喇辽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梨水,“玉大人,你說我怎么就攤上這事茵臭。” “怎么了舅世?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵旦委,是天一觀的道長。 經(jīng)常有香客問我雏亚,道長缨硝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任罢低,我火速辦了婚禮查辩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘网持。我一直安慰自己宜岛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布功舀。 她就那樣靜靜地躺著萍倡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辟汰。 梳的紋絲不亂的頭發(fā)上列敲,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音帖汞,去河邊找鬼戴而。 笑死,一個胖子當(dāng)著我的面吹牛翩蘸,可吹牛的內(nèi)容都是我干的所意。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扁眯!你這毒婦竟也來了壮莹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤姻檀,失蹤者是張志新(化名)和其女友劉穎命满,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绣版,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡胶台,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了杂抽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诈唬。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缩麸,靈堂內(nèi)的尸體忽然破棺而出铸磅,到底是詐尸還是另有隱情,我是刑警寧澤杭朱,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布阅仔,位于F島的核電站,受9級特大地震影響弧械,放射性物質(zhì)發(fā)生泄漏八酒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一刃唐、第九天 我趴在偏房一處隱蔽的房頂上張望羞迷。 院中可真熱鬧,春花似錦画饥、人聲如沸衔瓮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽报辱。三九已至,卻和暖如春单山,著一層夾襖步出監(jiān)牢的瞬間碍现,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工米奸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留昼接,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓悴晰,卻偏偏與公主長得像慢睡,于是被迫代替她去往敵國和親逐工。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容