ReactiveCocoa學習總結

来源:http://www.cnblogs.com/wujy/archive/2016/02/02/5177819.html
-Advertisement-
Play Games

最近一直斷斷續續學習關於ReactiveCocoa的知識內容,對於它的一些基礎內容將通過本文進行一個總結,主要是一些入門知識 一:RACSignal一些運用 @interface RACSignalTestViewController () @property(nonatomic,strong)RA


最近一直斷斷續續學習關於ReactiveCocoa的知識內容,對於它的一些基礎內容將通過本文進行一個總結,主要是一些入門知識

一:RACSignal一些運用

@interface RACSignalTestViewController ()
@property(nonatomic,strong)RACSignal *mySignal,*secondSingl;
@end
-(RACSignal *)mySignal
{
    if (!_mySignal) {
        _mySignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@10];
            [subscriber sendCompleted];
            return nil;
        }];
    }
    
    return _mySignal;
}

-(RACSignal *)secondSingl
{
    if (!_secondSingl) {
        _secondSingl=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@20];
            [subscriber sendCompleted];
            return nil;
        }];
    }
    return _secondSingl;
}

先創建兩個RACSignal的內容;將用於接下來的一些操作

    //map運用 返回的值作為next的參數
    [[self.mySignal map:^id(NSNumber *value) {
        return [value integerValue]>5?@"踏浪帥":@"有點小";
    }] subscribeNext:^(NSString *str) {
        NSLog(@"map處理完成的值為:%@",str);
    }];
    
    //filter:過濾信號,使用它可以獲取滿足條件的信號.
    [[self.mySignal filter:^BOOL(NSNumber *item) {
        return [item integerValue]>5;
    }] subscribeNext:^(NSNumber *x) {
        NSLog(@"filter當前的值%ld",[x integerValue]);
    }];
    
    
    //ignore:忽略完某些值的信號.當答合被ignore的值時就不會執行next
    [[self.mySignal ignore:@10] subscribeNext:^(id x) {
        NSLog(@"ignore當前的值:%@",x);
    }];
    
    //distinctUntilChanged:當上一次的值和當前的值有明顯的變化就會發出信號,否則會被忽略掉。
    [[self.mySignal distinctUntilChanged] subscribeNext:^(id x) {
        NSLog(@"distinctUntilChanged當前的值:%@",x);
    }];
    
    //take:從開始一共取N次的信號
    //takeLast:取最後N次的信號,前提條件,訂閱者必須調用完成,因為只有完成,就知道總共有多少信號.
    //takeUntil:(RACSignal *):獲取信號直到某個信號執行完成
    //skip:(NSUInteger):跳過幾個信號,不接受。

運行結果:

MobileProject[885:18784] map處理完成的值為:踏浪帥
2016-02-02 16:03:07.643 MobileProject[885:18784] filter當前的值10
2016-02-02 16:03:07.644 MobileProject[885:18784] distinctUntilChanged當前的值:10

1.2:一些組合的操作

    //concat:按一定順序拼接信號,當多個信號發出的時候,有順序的接收信號
    RACSignal *concatSignal=[self.mySignal concat:self.secondSingl];
    [concatSignal subscribeNext:^(id x) {
        NSLog(@"concat拼接的值:%@",x);
    }];

    
    //then:用於連接兩個信號,當第一個信號完成,才會連接then返回的信號
    [[self.mySignal then:^RACSignal *{
        @strongify(self);
        return self.secondSingl;
    }] subscribeNext:^(id x) {
        //// 只能接收到第二個信號的值,也就是then返回信號的值
        NSLog(@"then當前的值為:%@",x);
    }];
    
    
    //merge:把多個信號合併為一個信號,任何一個信號有新值的時候就會調用
    RACSignal *mergeSignal=[self.mySignal merge:self.secondSingl];
    [mergeSignal subscribeNext:^(id x) {
        NSLog(@"merge當前的值為:%@",x);
    }];
    
    
    //combineLatest:將多個信號合併起來,並且拿到各個信號的最新的值,必須每個合併的signal至少都有過一次sendNext,兩個信號的內容合併成一個元組RACTuple,才會觸發合併的信號。
    RACSignal *combineLatestSignal=[self.mySignal combineLatestWith:self.secondSingl];
    [combineLatestSignal subscribeNext:^(id x) {
        NSLog(@"combineLastest當前的值為:%@",x);
    }];
    
    
    //zipWith:把兩個信號壓縮成一個信號,只有當兩個信號同時發出信號內容時,並且把兩個信號的內容合併成一個元組RACTuple,才會觸發壓縮流的next事件。
    RACSignal *zipWithSignal=[self.mySignal zipWith:self.secondSingl];
    [zipWithSignal subscribeNext:^(RACTuple *tuple) {
        NSLog(@"zipWith當前的值為:%@",tuple);
        
        NSLog(@"zipWith中的RACTuple共有幾個值:%ld",tuple.count);
        
        NSLog(@"zipWith中的RACTuple第一個值為:%@",tuple.first);
        
        NSLog(@"zipWith中的RACTuple最後一個值為:%@",tuple.last);
    }];
    
    
    //reduce聚合:用於信號發出的內容是元組,把信號發出元組的值聚合成一個值 特別是combineLatestWith,zipWith這種返回元組的RACTuple,reduceblcok中的參數,有多少信號組合,reduceblcok就有多少參數,每個參數就是之前信號發出的內容
    RACSignal *reduceSignal=[RACSignal combineLatest:@[self.mySignal,self.secondSingl] reduce:^id(NSNumber *num1 ,NSNumber *num2){
        NSLog(@"combineLastest結合reduct的第一個值為:%ld 第二個值為:%ld",[num1 integerValue],[num2 integerValue]);
        return ([num1 integerValue]>10&&[num2 integerValue]>15)?@"兩個都符合要求":@"都沒有答合要求";
    }];
    [reduceSignal subscribeNext:^(id x) {
        NSLog(@"reduce當前的值為:%@",x);
    }];

運行結果:

MobileProject[885:18784] concat拼接的值:10
2016-02-02 16:03:07.645 MobileProject[885:18784] concat拼接的值:20
2016-02-02 16:03:07.646 MobileProject[885:18784] then當前的值為:20
2016-02-02 16:03:07.646 MobileProject[885:18784] merge當前的值為:10
2016-02-02 16:03:07.646 MobileProject[885:18784] merge當前的值為:20
2016-02-02 16:03:07.647 MobileProject[885:18784] combineLastest當前的值為:<RACTuple: 0x7ff5ca606860> (
    10,
    20
)
2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith當前的值為:<RACTuple: 0x7ff5ca60ab80> (
    10,
    20
)
2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple共有幾個值:2
2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple第一個值為:10
2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple最後一個值為:20
2016-02-02 16:03:07.649 MobileProject[885:18784] combineLastest結合reduct的第一個值為:10 第二個值為:20
2016-02-02 16:03:07.720 MobileProject[885:18784] reduce當前的值為:都沒有答合要求

1.3:其它一些操作:

    //doNext: 執行Next之前,會先執行這個Block,可以做一些初使化的功能,doCompleted: 執行sendCompleted之前,會先執行這個Block
    [[[self.mySignal doNext:^(id x) {
        NSLog(@"doNext當前的值:%@",x);
    }] doCompleted:^{
        NSLog(@"doComplete 執行到了");
    }] subscribeNext:^(id x) {
        NSLog(@"測試doNext,doComplete的值:%@",x);
    }];
    
    //switchToLatest:用於signalOfSignals(信號的信號),有時候信號也會發出信號,會在signalOfSignals中,獲取signalOfSignals發送的最新信號。
    RACSubject *signalOfSignals = [RACSubject subject];
    RACSubject *signal = [RACSubject subject];
    
    // 獲取信號中信號最近發出信號,訂閱最近發出的信號。
    // 註意switchToLatest:只能用於信號中的信號
    [signalOfSignals.switchToLatest subscribeNext:^(id x) {
        
        NSLog(@"switchToLatest%@",x);
    }];
    [signalOfSignals sendNext:signal];
    [signal sendNext:@1];
    
    //deliverOn: 內容傳遞切換到制定線程中,副作用在原來線程中,把在創建信號時block中的代碼稱之為副作用。
    //subscribeOn: 內容傳遞和副作用都會切換到制定線程中。'
    
    
    //timeout:超時,可以讓一個信號在一定的時間後,自動報錯。
    [[self.mySignal timeout:1 onScheduler:[RACScheduler currentScheduler]]
     subscribeNext:^(id x) {
         NSLog(@"timeout當前的值:%@",x);
     } error:^(NSError *error) {
         NSLog(@"timeout 超時了");
     }];
    
    
    //delay 延遲發送next。
    [[self.mySignal delay:2] subscribeNext:^(id x) {
        NSLog(@"delay執行%@",x);
    }];
    
    
    //retry重試 :只要失敗,就會重新執行創建信號中的block,直到成功.
    __block int i = 0;
    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        if (i == 10) {
            [subscriber sendNext:@100];
        }else{
            NSLog(@"接收到錯誤");
            [subscriber sendError:nil];
        }
        i++;
        
        return nil;
        
    }] retry] subscribeNext:^(id x) {
        
        NSLog(@"retry當前的值:%@",x);
        
    } error:^(NSError *error) {
        
    }];
    
    
    //普通執行多次訂閱
    RACSignal *oneSignal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        return nil;
    }] replay];
    [oneSignal subscribeNext:^(id x) {
        NSLog(@"第一個沒有replay執行的內容:%@",x);
    }];
    [oneSignal subscribeNext:^(id x) {
        NSLog(@"第二個沒有replay執行的內容:%@",x);
    }];
    
    
    //replay重放:當一個信號被多次訂閱,反覆播放內容
    RACSignal *replaySignal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        return nil;
    }] replay];
    
    [replaySignal subscribeNext:^(id x) {
        NSLog(@"replay第一個訂閱者%@",x);
    }];
    
    [replaySignal subscribeNext:^(id x) {
        NSLog(@"replay第二個訂閱者%@",x);
    }];
    
    
    //interval 定時:每隔一段時間發出信號
    [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
        NSLog(@"interval一直在執行:%@",x);
    }];
    
    //throttle節流:當某個信號發送比較頻繁時,可以使用節流,在某一段時間不發送信號內容,過了一段時間獲取信號的最新內容發出。

運行結果:

2016-02-02 16:03:07.720 MobileProject[885:18784] doNext當前的值:10
2016-02-02 16:03:07.720 MobileProject[885:18784] 測試doNext,doComplete的值:10
2016-02-02 16:03:07.721 MobileProject[885:18784] doComplete 執行到了
2016-02-02 16:03:07.721 MobileProject[885:18784] switchToLatest1
2016-02-02 16:03:07.722 MobileProject[885:18784] timeout當前的值:10
2016-02-02 16:03:07.722 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.723 MobileProject[885:18784] 第一個沒有replay執行的內容:1
2016-02-02 16:03:07.723 MobileProject[885:18784] 第一個沒有replay執行的內容:2
2016-02-02 16:03:07.723 MobileProject[885:18784] 第二個沒有replay執行的內容:1
2016-02-02 16:03:07.723 MobileProject[885:18784] 第二個沒有replay執行的內容:2
2016-02-02 16:03:07.724 MobileProject[885:18784] replay第一個訂閱者1
2016-02-02 16:03:07.724 MobileProject[885:18784] replay第一個訂閱者2
2016-02-02 16:03:07.724 MobileProject[885:18784] replay第二個訂閱者1
2016-02-02 16:03:07.724 MobileProject[885:18784] replay第二個訂閱者2
2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.839 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.866 MobileProject[885:18784] 接收到錯誤
2016-02-02 16:03:07.866 MobileProject[885:18784] retry當前的值:100
2016-02-02 16:03:08.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:08 +0000
2016-02-02 16:03:09.724 MobileProject[885:18784] delay執行10
2016-02-02 16:03:09.725 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:09 +0000
2016-02-02 16:03:10.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:10 +0000
2016-02-02 16:03:11.724 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:11 +0000
2016-02-02 16:03:12.727 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:12 +0000
2016-02-02 16:03:13.725 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:13 +0000
2016-02-02 16:03:14.730 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:14 +0000
2016-02-02 16:03:15.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:15 +0000

 

二:關於RACCommand的一些知識

@interface TestRacViewController ()
@property(nonatomic,strong)UITextField *userNameText;
@property(strong,nonatomic)NSString *username;
@property(nonatomic,strong)UIButton *loginButton,*racCommendButton,*errCommendButton,*mainThreadButton,*netWorkButton,*testButton;

@property(nonatomic,strong)RACCommand *otherMyRaccomand,*mainThreadCommend,*netWorkCommend,*testPropertyCommend;
@end

 

//佈局
-(void)loadPage
{
    if (!self.userNameText) {
        self.userNameText=[[UITextField alloc]init];
        self.userNameText.backgroundColor=[UIColor whiteColor];
        self.userNameText.placeholder=@"輸入用戶名";
        [self.view addSubview:self.userNameText];
        [self.userNameText mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.view.mas_top).with.offset(70);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.loginButton)
    {
        self.loginButton=[[UIButton alloc]init];
        [self.loginButton setTitle:@"響應" forState:UIControlStateNormal];
        self.loginButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.loginButton];
        [self.loginButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.userNameText.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.racCommendButton)
    {
        self.racCommendButton=[[UIButton alloc]init];
        [self.racCommendButton setTitle:@"RacCommend測試" forState:UIControlStateNormal];
        self.racCommendButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.racCommendButton];
        [self.racCommendButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.loginButton.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.errCommendButton)
    {
        self.errCommendButton=[[UIButton alloc]init];
        [self.errCommendButton setTitle:@"ERROR測試" forState:UIControlStateNormal];
        self.errCommendButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.errCommendButton];
        [self.errCommendButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.racCommendButton.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.mainThreadButton)
    {
        self.mainThreadButton=[[UIButton alloc]init];
        [self.mainThreadButton setTitle:@"主線程上運行" forState:UIControlStateNormal];
        self.mainThreadButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.mainThreadButton];
        [self.mainThreadButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.errCommendButton.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.netWorkButton)
    {
        self.netWorkButton=[[UIButton alloc]init];
        [self.netWorkButton setTitle:@"屬性測試" forState:UIControlStateNormal];
        self.netWorkButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.netWorkButton];
        [self.netWorkButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.mainThreadButton.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
    
    if(!self.testButton)
    {
        self.testButton=[[UIButton alloc]init];
        [self.testButton setTitle:@"測試特性" forState:UIControlStateNormal];
        self.testButton.backgroundColor=[UIColor blueColor];
        [self.view addSubview:self.testButton];
        [self.testButton mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(self.view.mas_left).with.offset(15);
            make.top.mas_equalTo(self.netWorkButton.mas_bottom).with.offset(20);
            make.right.mas_equalTo(self.view.mas_right).with.offset(-15);
            make.height.mas_equalTo(@40);
        }];
    }
}

一些定義

//創建一個信號代碼
-(RACSignal *)testSignal
{
    RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"創建信號");
        [subscriber sendNext:@"Hi 我是一個信號"];
        [subscriber sendCompleted];
        return nil;
    }];
    return signal;
}

//創建一個命令響應
-(RACCommand *)testCommend
{
    @weakify(self);
    RACCommand *myCommend=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        RACSignal *authSignal=[RACSignal empty];
        @strongify(self);
    
                  authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                      //可以根據要求加條件進行判斷是否創建信號
                      if ([self.username isEqualToString:@"wjy"]) {
                      NSLog(@"符合要求");
                      [subscriber sendNext:@"我完成的命令響應"];
                      [subscriber sendCompleted];
                      }
                      else
                      {
                          //錯誤
                          [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]];
                      }
                  return nil;
            }];
        //materialize是為了處理拿不到error的問題
        return [authSignal materialize];
    }];
    
    return myCommend;
}

//創建屬性的RACCommand
-(RACCommand *)otherMyRaccomand
{
    if (!_otherMyRaccomand) {
        _otherMyRaccomand=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            NSLog(@"執行到新的RACCommand");
            RACSignal *otherSignal=[RACSignal empty];
            otherSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                if ([self.username isEqualToString:@"wjy"]) {
                    [subscriber sendNext:@"我肯定可以運行的"];
                    [subscriber sendCompleted];
                }
                else
                {
                    [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:401 userInfo:nil]];
                }
                return nil;
            }];
            return otherSignal;
        }];
    }
    return _otherMyRaccomand;
}


//創建主線程上運行
-(RACCommand *)mainThreadCommend
{
    @weakify(self);
    if (!_mainThreadCommend) {
    _mainThreadCommend=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        RACSignal *authSignal=[RACSignal empty];
        @strongify(self);
        
        authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            @strongify(self);
            //可以根據要求加條件進行判斷是否創建信號
            if ([self.username isEqualToString:@"wjy"]) {
                [subscriber sendNext:@(YES)];
                [subscriber sendCompleted];
            }
            else
            {
                //錯誤
                [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]];
            }
            return nil;
        }];
        return authSignal;
    }];
    }
    return _mainThreadCommend;
}


//特性測試
-(RACCommand *)testPropertyCommend
{
    if (!_testPropertyCommend) {
        
    }
    
    return _testPropertyCommend;
}

-(RACSignal *)nettestSignal
{
    RACSignal *authSignal=[RACSignal empty];
    
    authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        LogInApi *reg = [[LogInApi alloc] initWithUsername:self.username password:@"123456"];
        [reg startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {
            LoginModel *model=[[LoginModel alloc]initWithString:request.responseString error:nil];
            [subscriber sendNext:model];
            [subscriber sendCompleted];
        } failure:^(YTKBaseRequest *request) {
            [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]];
        }];
        return nil;
    }];
    return authSignal;
}

-(RACSignal *)netSignal
{
    RACSignal *authSignal=[RACSignal empty];
    authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"測試"];
        [subscriber sendCompleted];

        return nil;
    }];
    return authSignal;
}

//RACSubject的運用
-(RACSubject *)testSubject
{
    RACSubject *sub=[RACSubject subject];
    [sub sendNext:@"我是RACSubject"];
    return sub;
}

運用的內容:

    [self loadPage];

    @weakify(self);
    
    //把左邊的屬性跟右邊信號signal的sendNext值綁定  distinctUntilChanged為了當值相同時不執行
    RAC(self,username)=[self.userNameText.rac_textSignal distinctUntilChanged];
    
    //監聽username是否有變化,有變化就會執行subscribeNext 這個屬性要支持KVO  可變數組就不可以
    [RACObserve(self, username) subscribeNext:^(NSString *x) {
        NSLog(@"你當前輸入的值為:%@",x);
    }];
    
    //UIAlertView跟RAC結合
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"" message:@"Alert" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
    [[alertView rac_buttonClickedSignal] subscribeNext:^(NSNumber *indexNumber) {
        if ([indexNumber intValue] == 1) {
            NSLog(@"你點了確定");
        } else {
            NSLog(@"你點了取消");
        }
    }];
    [alertView show];
    
    //Button響應事件
    [[self.loginButton
      rac_signalForControlEvents:UIControlEventTouchUpInside]
        subscribeNext:^(UIButton *x) {
         @strongify(self);
         [[self testSignal] subscribeNext:^(id x) {
             NSLog(@"當前執行值為:%@",x);
         }];
     }];
    
    
    
    //Button用命令式運行 switchToLatest處理信號中傳遞的參數為信號
    self.racCommendButton.rac_command=[self testCommend];
    
    //這個綁定要放在executionSignals執行前面 否則只會有一個執行完成會響應
    [self.racCommendButton.rac_command.executing subscribeNext:^(id x) {
        if ([x boolValue]) {
            NSLog(@"rac_command正在執行中");
        }
        else
        {
            NSLog(@"rac_command執行完成");
        }
    }];
    
    //dematerialize處理可以響應處理跟完成的內容
    [self.racCommendButton.rac_command.executionSignals subscribeNext:^(RACSignal *execution) {
        [[[execution dematerialize] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
            NSLog(@"提示內容:%@",x);
        } error:^(NSError *error) {
             NSLog(@"racCommend出錯了");
        }];
    }];
    
    
    //關於otherMyRaccomand的方式
    self.errCommendButton.rac_command=self.otherMyRaccomand;
    
    [self.otherMyRaccomand.executionSignals.switchToLatest subscribeNext:^(id x) {
        NSLog(@"完成了 %@",x);
    }];
    
    //這邊要註意是在errors 裡面執行subscribeNext   不是執行subscribeError
    [self.otherMyRaccomand.errors subscribeNext:^(NSError *error) {
        NSLog(@"出錯了 %@",error);
    }];
    
    
    //主線程上操作
    self.mainThreadButton.rac_command=self.mainThreadCommend;
    [[[self.mainThreadCommend.executionSignals.switchToLatest map:^id(id value) {
        if ([value boolValue]) {
            return @"跳浪帥";
        }
        else
        {
            return @"出太陽好麽";
        }
    }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSString *str) {
        UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"我是彈出窗" message:[NSString stringWithFormat:@"%@",str] delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
        [alert show];
    }];
    
    //網路請求
    //Button響應事件
    [[self.netWorkButton
      rac_signalForControlEvents:UIControlEventTouchUpInside]
     subscribeNext:^(id x) {
         [[[self netSignal] flattenMap:^RACStream *(id value) {
              return [RACReturnSignal return:[NSString stringWithFormat:@"%@ 我已經被改變了成為另外一個信號",value]];
         }]
         subscribeNext:^(id x) {
             NSLog(@"輸出的內容:%@",x);
         }];
         
     }];
    

三:雙向綁定

RACChannelTerminal *channelA = RACChannelTo(self, valueA);
    RACChannelTerminal *channelB = RACChannelTo(self, valueB);
    [[channelA map:^id(NSString *value) {
        if ([value isEqualToString:@"西"]) {
            return @"東";
        }
        return value;
    }] subscribe:channelB];
    [[channelB map:^id(NSString *value) {
        if ([value isEqualToString:@"左"]) {
            return @"右";
        }
        return value;
    }] subscribe:channelA];
    [[RACObserve(self, valueA) filter:^BOOL(id value) {
        return value ? YES : NO;
    }] subscribeNext:^(NSString* x) {
        NSLog(@"你向%@", x);
    }];
    [[RACObserve(self, valueB) filter:^BOOL(id value) {
        return value ? YES : NO;
    }] subscribeNext:^(NSString* x) {
        NSLog(@"他向%@", x);
    }];
    self.valueA = @"西";
    self.valueB = @"左";
2015-08-15 20:14:46.544 Test[2440:99901] 你向西  
2015-08-15 20:14:46.544 Test[2440:99901] 他向東  
2015-08-15 20:14:46.545 Test[2440:99901] 他向左  
2015-08-15 20:14:46.545 Test[2440:99901] 你向右

一個關於左右列表相互影響滾動的雙向綁定實例:

    RACChannelTerminal *leftChannel = RACChannelTo(self.leftTableView, contentOffset);
    RACChannelTerminal *rightChannel = RACChannelTo(self.rightTableView, contentOffset);
    [[rightChannel map:^id(NSValue *offset) {
        CGPoint point = offset.CGPointValue;
        point.y /= 10;
        return [NSValue valueWithCGPoint:point];
    }] subscribe:leftChannel];
    [[leftChannel map:^id(NSValue *offset) {
        CGPoint point = offset.CGPointValue;
        point.y *= 10;
        return [NSValue valueWithCGPoint:point];
    }] subscribe:rightChannel];

一個輸入內容自動計算:

    RACChannelTerminal *characterRemainingTerminal = RACChannelTo(_loginButton, titleLabel.text);
    
    [[self.userNameText.rac_textSignal map:^id(NSString *text) {
        return [@(100 - (NSInteger)text.length) stringValue];
    }] subscribe:characterRemainingTerminal];

 二個輸入框相互影響:

RACChannelTerminal *textField1Channel = [view.textField1 rac_newTextChannel];
RACChannelTerminal *textField2Channel = [view.textField2 rac_newTextChannel];
 
[textField1Channel subscribe:textField2Channel];
[textField2Channel subscribe:textField1Channel];

 四:重點類的說明

1: streams
streams代表任意的值,其值會隨著事件發⽣變化,由RACStream類表⽰。值可能⻢上可⽤,或者
在將來某⼀段時間可⽤,但必須按順序獲取,也就是說,在獲取到第⼀個值之前,是不可能獲取到
第⼆個值。
streams 是⼀個構造因果關係的結構(Monad), 要瞭解這個概念可以看這篇⽂章:http://
blog.csdn.net/ensoo/article/details/7506872。它可以實現在基本的初始值上進⾏複雜的操作運算
(filter,map,reducet等)。
streams不會被經常使⽤,⼤多情況下表現為signal和sequences,即Signal和Sequence是由stream
繼承。
2:Signals
Signals由RACSignal類表⽰。
Signals⼀般表⽰將來被傳遞的數據。當信號接收到數據時,值就會通過signal被髮送出去,它推送
數據給訂閱者。⽤戶必須訂閱信號才能獲取到它的值。
Signals發送3種不同類型的事件給它的訂閱者:
1)next:next事件是stream提供了⼀個新值。⽽RACStream類的⽅法也只能在這個值上進⾏操作運
算。和cocoa的集合不同的是,它可以包含⼀個nil值。
2)error:error事件表⽰在信號完成之前發⽣了錯誤。這個事件包含了⼀個NSError類型的錯誤。這
個值不會在RACStream類⾥存儲。
3)completed事件:表⽰信號已經成功地完成了。這個值也不會在RACStream類⾥存儲。
3:Subscription
subscriber(訂閱者)表⽰等待或者能夠等待信號發送事件的任意對象。在框架中使⽤
RACSubscriber 協議表⽰,也即任意實現了RACSubscriber協議的對象都可以是訂閱者。
可以通過調⽤ -subscribeNext:error:completed:⽅法來創建訂閱。RACStream 和 RACSignal類的⼤
多操作也會⾃⼰創建訂閱。
訂閱會對Signals對象引⽤計數加1,當信號發送錯誤或者完成事件後,會⾃動被處理,不需要⽤戶
關⼼記憶體管理。當然,⽤戶也可以⼿動處理。
4: Subjects
subject由RACSubject類表⽰,它是可以⼿動控制的信號。
subject可以想成是signal的變體,就像NSMutableArray相對於NSArray⼀樣。它們是⾮RAC的代碼
和RAC代碼之間的橋梁,因此,⾮常有⽤。
有些subject提供了額外的功能。特別地,RACReplaySubject⽤於緩存事件,將來有訂閱者時,可以
將緩存的數據發送給訂閱者,⽐如,當請求⼀個⺴絡時,伺服器數據已經返回,但其它的數據還沒
有準備好,這時,先要將⺴絡請求結果緩存,等其它數據準備好時,再訂閱,⽽不⾄於⺴絡請求數
據丟失。
5:Commands
command由RACCommand 類表⽰,它創建並訂閱響應action的信號。
通常command是由UI觸發的,像⼀個按鈕被點擊時。當command被觸發時,控制項會⾃動被禁⽤。
6:Connections
connection由RACMulticastConnection類表⽰。它是在任意數量的訂閱者之間共用訂閱。
預設情況下,信號沒有訂閱時,是冷信號,也即當有訂閱者被添加進來後,信號才會開始⼯作,也
即變為熱信號。
這也是期望的⾏為,對於每個訂閱,數據值都會被延遲重新計算。否則,如果信號有副作⽤或者任
務開銷很⼤時,可能就會產⽣問題。
conection通過RACSignal的publish或者multicast⽅法創建, ⼀旦連接,信號就變為熱信息,訂閱會
保持激活狀態直到所有的訂閱連接被取消。
7:Sequences
sequence由RACSequence 類表⽰。
sequence是⼀種集合,類似於NSArray。和數組不同,為了改進性能,在sequence⾥的值會延遲計
算,也即,只有需要輸出值時,結果才會被計算。sequences和cocoa⾥的集合⼀樣,也不能包含nil
值。
對於⼤多數據的集合類,RAC添加了-rac_sequence ⽅法來⽣成RACSequence類進⾏操作。
8:Disposables
RACDisposable 類⽤於取消訂閱或者清理資源。
Disposables⼤多情況下⽤於取消信號的訂閱 。
9:Schedulers
scheduler由RACScheduler類表⽰,它是信號執⾏任務時所在的隊列(queue)或者信號執⾏完後將
結果放到隊列⾥執⾏,可以認為就是gcd⾥的queues。
scheduler⽀持取消操作,⽽且它總是串⾏地執⾏任務。這有利於避免死鎖。
RACScheduler有時候也類似NSOperationQueue,但它不允許任務間相互依賴。
10:Value types
RAC提供了以下類⽤於表⽰各種值:
1)RACTuple: ⼀個⽐較少數量值,⼤⼩固定的,可以包含nil的集合。⼀般⽤於表⽰多個streams
的聚合值。
2)RACUnit :⼀個單例的空值,表⽰stream不包含有意義的值。
3)RACEvent : 代表任意的信號事件。
11:Asynchronous Backtraces
由於基於RAC的代碼經常和非同步相關,因此,為了更⽅便調試,RAC⽀持捕獲當前的asynchronous
backtraces(非同步調⽤棧)。

五:副作用及消除副作用

__block int aNumber = 0;

// Signal that will have the side effect of incrementing `aNumber` block 
// variable for each subscription before sending it.
RACSignal *aSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
    aNumber++;
    [subscriber sendNext:@(aNumber)];
    [subscriber sendCompleted];
    return nil;
}];

// This will print "subscriber one: 1"
[aSignal subscribeNext:^(id x) {
    NSLog(@"subscriber one: %@", x);
}];

// This will print "subscriber two: 2"
[aSignal subscribeNext:^(id x) {
    NSLog(@"subscriber two: %@", x);
}];

上面這樣就會產生副作用,第一個跟第二個的值會不一樣,被累加;採用RACMulticastConnection來消除

    __block int aNumber = 0;
    
    // Signal that will have the side effect of incrementing `aNumber` block
    // variable for each subscription before sending it.
    RACSignal *aSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        aNumber++;
        [subscriber sendNext:@(aNumber)];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACMulticastConnection *connection = [aSignal multicast:[RACReplaySubject subject]];
    [connection connect];
    
    // This will print "subscriber one: 1"
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"subscriber one: %@", x);
    }];
    
    // This will print "subscriber two: 1"
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"subscriber two: %@", x);
    }];

這樣兩次都只返回相同的內容,為1;其同要註意是調用connection.signal;下麵是官網的一個網路請求實例:

RACSignal *networkRequest = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    AFHTTPRequestOperation *operation = [client
        HTTPRequestOperationWithRequest:request
        success:^(AFHTTPRequestOperation *operation, id response) {
            [subscriber sendNext:response];
            [subscriber sendCompleted];
        }
        failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            [subscriber sendError:error];
        }];

    [client enqueueHTTPRequestOperation:operation];
    return [RACDisposable disposableWithBlock:^{
        [operation cancel];
    }];
}];

// Starts a single request, no matter how many subscriptions `connection.signal`
// gets. This is equivalent to the -replay operator, or similar to
// +startEagerlyWithScheduler:block:.
RACMulticastConnection *connection = [networkRequest multicast:[RACReplaySubject subject]];
[connection connect];

[connection.signal subscribeNext:^(id response) {
    NSLog(@"subscriber one: %@", response);
}];

[connection.signal subscribeNext:^(id response) {
    NSLog(@"subscriber two: %@", response);
}];

這兩個訂閱者接收到了同樣的一個請求的內容。

 

六:工作原理

因為代碼中已經有相應的註解,所以文字說明就比較少,若有不明白可以留言;


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在AngularJS中如何實現一個Model的緩存呢?可以通過在Provider中返回一個構造函數,併在構造函數中設計一個緩存欄位,在本篇末尾將引出這種做法。一般來說,Model要賦值給Scope的某個變數。有的直接把對象賦值給Scope變數;有的在Provider中返回一個對象再賦值給Scope變
  • 在寫一個js圖片輪播的時候,遇到了一個瀏覽器報錯的問題,想了很久,後面解決了問題, 瀏覽器報錯如下: 在chrome瀏覽器報錯如下: Uncaught TypeError: Cannot read property 'style' of undefined 在firefox瀏覽器報錯如下: Type
  • Xcode7自2015年9上架以來也有段時間了, 使用Xcode7以及Xcode7.1\Xcode7.2的小伙伴會發現像VVDocumenter-Xcode\KSImageNamed-Xcode\HOStringSense-for-Xcode等等一系列的插件不能正常使用了,下麵我們就來解決一下該版本
  • 第一步 :獲取ShareSDK 為了集成ShareSDK,您首先需要到ShareSDK官方網站註冊並且創建應用,獲得ShareSDK的Appkey,然後到SDK的下載頁面下載SDK的壓縮包,解壓以後可以得到如下圖的目錄結構: ShareSDK在“ShareSDK for Android”目錄下,此目
  • 【原】AFNetworking源碼閱讀(六) 本文轉載請註明出處 —— polobymulberry-博客園 1. 前言 這一篇的想講的,一個就是分析一下AFSecurityPolicy文件,看看AFNetworking的網路安全策略,尤其指HTTPS(大家可以先簡單瞭解下HTTPS)。再一個就是分
  • 本文將從四個方面對IOS開發中UIAlertView與UIAlertController的用法進行講解: 一、UIAlertView與UIAlertController是什麼東東? 二、我們為什麼要用UIAlertView或UIAlertController? 三、如何使用UIAlertView和U
  • import java.io.ByteArrayOutputStream; /** * Created by Administrator on 2016/2/2. * -----------16進位和字元串互轉--------- * ------------解決中文亂碼問題--------- */
  • 在頁面中 載入了一個webView 當點擊該webView的頁面 需要獲取webView中的url。 在push出來的另一個頁面中,重新初始化一個webView載入 下麵這個方法 在webView載入的時候都會調用 loaded是一個BOOL類型的屬性 未設初始值 - (BOOL)webView:(
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...