麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

ReactiveCocoa基礎知識內容

2019-11-14 17:58:06
字體:
來源:轉載
供稿:網友

本文記錄一些關于學習ReactiveCocoa基礎知識內容,對于ReactiveCocoa相關的概念如果不了解可以網上搜索;RACSignal有很多方法可以來訂閱不同的事件類型,ReactiveCocoa框架使用category來為很多基本UIKit控件添加signal。本文有收集一些網上其它文章的實例跟內容;

一:先創建頁面布局(準備階段)

@interface ViewController ()@PRoperty(strong,nonatomic)UITextField *nameTextField;@property(strong,nonatomic)UILabel *contentLabel;@property(strong,nonatomic)UIButton *saveBtn;@end
    if (self.nameTextField==nil) {        self.nameTextField=[[UITextField alloc]init];        self.nameTextField.backgroundColor=[UIColor grayColor];        [self.view addSubview:self.nameTextField];        [self.nameTextField mas_makeConstraints:^(MASConstraintMaker *make) {            make.top.mas_equalTo(self.view.mas_top).with.offset(64);            make.left.mas_equalTo(self.view.mas_left).with.offset(0);            make.right.mas_equalTo(self.view.mas_right).with.offset(0);            make.height.mas_equalTo(@40);        }];    }        if (self.contentLabel==nil) {        self.contentLabel=[[UILabel alloc]init];        self.contentLabel.backgroundColor=[UIColor blueColor];        [self.view addSubview:self.contentLabel];        [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {            make.top.mas_equalTo(self.nameTextField.mas_bottom).with.offset(10);            make.left.mas_equalTo(self.view.mas_left).with.offset(0);            make.right.mas_equalTo(self.view.mas_right).with.offset(0);            make.height.mas_equalTo(@100);        }];    }        if (self.saveBtn==nil) {        self.saveBtn=[[UIButton alloc]init];        self.saveBtn.backgroundColor=[UIColor blackColor];        [self.saveBtn setTitle:@"提交" forState:UIControlStateNormal];        [self.view addSubview:self.saveBtn];        [self.saveBtn mas_makeConstraints:^(MASConstraintMaker *make) {            make.top.mas_equalTo(self.contentLabel.mas_bottom).with.offset(20);            make.left.mas_equalTo(self.view.mas_left).with.offset(30);            make.right.mas_equalTo(self.view.mas_right).with.offset(-30);            make.height.mas_equalTo(@40);        }];    }

注意:saveBtn這個沒有增加事件的調用代碼,可以直接運用ReactiveCocoa給它注冊事件,并把相應的操作綁定;

二:ReactiveCocoa小實例(控件創建完后直接把這些綁定在viewDidLoad中

1:UITextField的rac_textSignal,它會在文本發生變化時產生信號

    [self.nameTextField.rac_textSignal subscribeNext:^(id x) {        self.contentLabel.text=x;    }];

 效果:輸入馬上會把變化的值顯示出來;省去以前還要去監聽的操作;

2:filter條件過濾

    [[self.nameTextField.rac_textSignal filter:^BOOL(id value) {        NSString *text=value;        return text.length>3;    }] subscribeNext:^(id x) {        self.contentLabel.text=x;    }];

效果:只有輸入的字符串長度大于3才會顯示出來,顯示為字符串的內容;

3:拆分寫法,rac_textSignalfilter都是RACSignal

    RACSignal *nameRacSignal=self.nameTextField.rac_textSignal;    RACSignal *filteredName=[nameRacSignal filter:^BOOL(id value) {        NSString *text=value;        return text.length>3;    }];    [filteredName subscribeNext:^(id x) {        self.contentLabel.text=x;    }];

效果:跟實例2上面的效果一樣,只是分開定義;

4:上面所有的id類型都可以根據實際的情況進行類型對應

    [[self.nameTextField.rac_textSignal      filter:^BOOL(NSString *text){          return text.length > 3;      }]     subscribeNext:^(id x){          self.contentLabel.text=x;     }];

效果:這邊filter里面為NSString類型;其它也可以相應的對照比如int bool等,效果如上

5:map 改變當前的值傳給下個

    [[[self.nameTextField.rac_textSignal       map:^id(NSString *text){           return @(text.length);       }]      filter:^BOOL(NSNumber *length){          return [length intValue] > 3;      }]     subscribeNext:^(id x){         //記得轉換顯示 目前為NSNumber型         self.contentLabel.text=[NSString stringWithFormat:@"%@",x];     }];

效果:最后顯示為:4,5,6,7,8,9.....,不會再顯示字符串的內容,已經被map修改成length,所以filter參數也被改變了;運用可以用來轉換成相要的對象

    RAC(self.contentLabel, text) = [[[self.nameTextField.rac_textSignal                                      startWith:@"key is >3"] // startWith 一開始返回的初始值                                     filter:^BOOL(NSString *value) { // filter使滿足條件的值才能傳出                                         return value.length > 3;                                     }] map:^id(NSString *text) {  //當值為wujy時顯示為bingo!                                         return [text isEqualToString:@"wujy"] ? @"bingo!" : text;                                     }];

 

6:驗證有效性,并把對應的屬性進行修改(寫法不好,見7點,宏定義RAC)

    RACSignal *validUsernameSignal =    [self.nameTextField.rac_textSignal     map:^id(NSString *text) {         return @([self isValidUsername:text]);     }];        [[validUsernameSignal      map:^id(NSNumber *userNameValid){          return[userNameValid boolValue] ? [UIColor redColor]:[UIColor yellowColor];      }]     subscribeNext:^(UIColor *color){         self.contentLabel.backgroundColor = color;     }];方法代碼如下:-(BOOL)isValidUsername:(NSString *)userName{    if ([userName isEqualToString:@"wjy"]) {        return true;    }    else    {        return false;    }}

效果:只有當輸入的字符串為wjy時才會改變背景效果;

7:宏RAC的運用

    RACSignal *validUsernameSignal =        [self.nameTextField.rac_textSignal         map:^id(NSString *text) {             return @([self isValidUsername:text]);         }];    RAC(self.contentLabel,backgroundColor)=[validUsernameSignal                                            map:^id(NSNumber *userNameValid){                                                return[userNameValid boolValue] ? [UIColor redColor]:[UIColor yellowColor];                                            }];

效果:這種是簡化的寫法,直接用宏RAC進行,可以在目前的管道中移除subscribeNext:block,轉而使用RAC宏

說明:RAC宏允許直接把信號的輸出應用到對象的屬性上。RAC宏有兩個參數,第一個是需要設置屬性值的對象,第二個是屬性名。每次信號產生一個next事件,傳遞過來的值都會應用到該屬性上。也可以有三個參數:RAC(self.outputLabel, text, @"收到nil時就顯示我") = self.inputTextField.rac_textSignal;第三個是為nil時顯示的內容;

8:聚合信號(引用)

RACSignal *validUsernameSignal = [self.usernameTextField.rac_textSignal map:^id(NSString *text) { return @([self isValidUsername:text]); }]; RACSignal *validPassWordSignal = [self.passwordTextField.rac_textSignal  map:^id(NSString *text) {  return @([self isValidPassword:text]); }];
RACSignal *signUpActiveSignal =  [RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]                    reduce:^id(NSNumber*usernameValid, NSNumber *passwordValid){                      return @([usernameValid boolValue]&&[passwordValid boolValue]);                    }];
[signUpActiveSignal subscribeNext:^(NSNumber*signupActive){   self.signInButton.enabled =[signupActive boolValue]; }];

說明:RACsignal的這個方法可以聚合任意數量的信號,reduce block的參數和每個源信號相關。ReactiveCocoa有一個工具類RACBlockTrampoline,它在內部處理reduce block的可變參數。

效果:上面的代碼使用combineLatest:reduce:方法把validUsernameSignalvalidPasswordSignal產生的最新的值聚合在一起,并生成一個新的信號。每次這兩個源信號的任何一個產生新值時,reduce block都會執行,block的返回值會發給下一個信號。

9:UIButton事件rac_signalForControlEvents

    [[self.saveBtn      rac_signalForControlEvents:UIControlEventTouchUpInside]     subscribeNext:^(id x) {         NSLog(@"button clicked");     }];

效果:點擊事件響應

10:doNext

    [[[self.saveBtn      rac_signalForControlEvents:UIControlEventTouchUpInside]     doNext:^(id x) {         self.contentLabel.backgroundColor=[UIColor greenColor];     } ]     subscribeNext:^(id x) {         NSLog(@"button clicked");         self.contentLabel.backgroundColor=[UIColor redColor];     }];

說明doNext:是直接跟在按鈕點擊事件的后面。而且doNext: block并沒有返回值。因為它是附加操作,并不改變事件本身,功能如:上面的doNext: block把按鈕置為不可點擊,隱藏登錄失敗提示。然后在subscribeNext: block里重新把按鈕置為可點擊,并根據登錄結果來決定是否顯示失敗提示。實例如下

    實例:    [[[[self.saveBtn        rac_signalForControlEvents:UIControlEventTouchUpInside]       doNext:^(id x){           self.signInButton.enabled =NO;           self.signInFailureText.hidden =YES;       }]      flattenMap:^id(id x){          return[self signInSignal];      }]     subscribeNext:^(NSNumber*signedIn){         self.signInButton.enabled =YES;         BOOL success =[signedIn boolValue];         self.signInFailureText.hidden = success;         if(success){             [self performSegueWithIdentifier:@"signInSuccess" sender:self];         }     }];

 11:RACObserve運用

RAC(self.outputLabel, text) = RACObserve(self.model, name); 

上面的代碼將label的輸出和model的name屬性綁定,實現聯動,name但凡有變化都會使得label輸出

實例:

    self.myModel=[[userModel alloc]init];    RAC(self.contentLabel, text) = RACObserve(self.myModel, name);        [[self.saveBtn          rac_signalForControlEvents:UIControlEventTouchUpInside]         subscribeNext:^(id x) {             self.myModel.name=@"wujysfsfsdfsf";        }];

注意:userModel是自定義的一個實體,里面只有一個name的屬性,上面運用時記得實例化;

12:自定義信號RACSubject(繼承自RACSignal,可以理解為自由度更高的signal)

- (void)doTest{    RACSubject *subject = [self doRequest];        [subject subscribeNext:^(NSString *value){        NSLog(@"value:%@", value);    }];}- (RACSubject *)doRequest{    RACSubject *subject = [RACSubject subject];    // 模擬2秒后得到請求內容    // 只觸發1次    // 盡管subscribeNext什么也沒做,但如果沒有的話map是不會執行的    // subscribeNext就是定義了一個接收體    [[[[RACSignal interval:2] take:1] map:^id(id _){        // the value is from url request        NSString *value = @"content fetched from web";        [subject sendNext:value];        return nil;    }] subscribeNext:^(id _){}];    return subject;}

 13:ignore

    [[self.nameTextField.rac_textSignal ignore:@"wjy"] subscribeNext:^(NSString *value) {        NSLog(@"當輸入為wjy時會被忽略: %@", value);    }];

說明:忽略給定的值,注意,這里忽略的既可以是地址相同的對象,也可以是- isEqual:結果相同的值,也就是說自己寫的Model對象可以通過重寫- isEqual:方法來使- ignore:生效。

 14:distinctUntilChanged

    self.myModel=[[userModel alloc]init];    RAC(self.contentLabel, text) = [RACObserve(self.myModel, name) distinctUntilChanged];    self.myModel.name = @"第一次"; // 1st    self.myModel.name  = @"第一次"; // 2nd    self.myModel.name = @"第一次"; // 3rd

說明:它將這一次的值與上一次做比較,當相同時(也包括- isEqual:)被忽略掉。如果不增加distinctUntilChanged的話對于連續的相同的輸入值就會有不必要的處理,這個實例只是簡單的UI刷新,但遇到如寫數據庫,發網絡請求的情況時,代價就不能購忽略了。

 15:起止點過濾類型

除了被動的當next值來的時候做判斷,也可以主動的提前選擇開始和結束條件,分為兩種類型:take型(取)和skip型(跳)

a:-take: (NSUInteger)

[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {    [subscriber sendNext:@"1"];    [subscriber sendNext:@"2"];    [subscriber sendNext:@"3"];    [subscriber sendCompleted];    return nil;}] take:2] subscribeNext:^(id x) {    NSLog(@"only 1 and 2 will be print: %@", x);}];

說明:從開始一共取N次的next值,不包括CompetionError

b:takeLast: (NSUInteger)

取最后N次的next值,注意,由于一開始不能知道這個Signal將有多少個next值,所以RAC實現它的方法是將所有next值都存起來,然后原Signal完成時再將后N個依次發送給接收者,但Error發生時依然是立刻發送的。

c:takeUntil:(RACSignal *)

- (RACSignal *)rac_textSignal {    @weakify(self);    return [[[[[RACSignal        concat:[self rac_signalForControlEvents:UIControlEventEditingChanged]]        map:^(UITextField *x) {            return x.text;        }]        takeUntil:self.rac_willDeallocSignal] // bingo!}

當給定的signal完成前一直取值,也就是這個Signal一直到textField執行dealloc時才停止

d:takeUntilBlock:(BOOL (^)(id x))

[[self.inputTextField.rac_textSignal takeUntilBlock:^BOOL(NSString *value) {    return [value isEqualToString:@"stop"];}] subscribeNext:^(NSString *value) {    NSLog(@"current value is not `stop`: %@", value);}];

對于每個next值,運行block,當block返回YES時停止取值

e:takeWhileBlock:(BOOL (^)(id x))

上面的反向邏輯,對于每個next值,block返回 YES時才取值

f:skip:(NSUInteger)

[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {    [subscriber sendNext:@"1"];    [subscriber sendNext:@"2"];    [subscriber sendNext:@"3"];    [subscriber sendCompleted];    return nil;}] skip:1] subscribeNext:^(id x) {    NSLog(@"only 2 and 3 will be print: %@", x);}];

從開始跳過N次的next值

g:skipUntilBlock:(BOOL (^)(id x))

- takeUntilBlock:同理,一直跳,直到block為YES

h:skipWhileBlock:(BOOL (^)(id x))

- takeWhileBlock:同理,一直跳,直到block為NO

 

 16:創建信號

    RACSignal *nameSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@"www.companysz.com/wujy"];        [subscriber sendCompleted];        return nil;    }];        [nameSignal subscribeNext:^(id x) {        NSLog(@"當前輸入的值為%@",x);    }];

另外一種比較完整的寫法:

-(RACSignal *)urlResults {    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        NSError *error;        NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.devtang.com"]                                                    encoding:NSUTF8StringEncoding                                                       error:&error];        NSLog(@"download");        if (!result) {            [subscriber sendError:error];        } else {            [subscriber sendNext:result];            [subscriber sendCompleted];        }        return [RACDisposable disposableWithBlock:^{            NSLog(@"clean up");        }];    }];}

如果還沒有被Next時它就是冷信號,只有被調用時才是熱信號;

說明:Signal and Subscriber是RAC最核心的內容,這里我想用插頭和插座來描述,插座是Signal,插頭是Subscriber。想象某個遙遠的星球,他們的電像某種物質一樣被集中存儲,且很珍貴。插座負責去獲取電,插頭負責使用電,而且一個插座可以插任意數量的插頭。當一個插座(Signal)沒有插頭(Subscriber)時什么也不干,也就是處于冷(Cold)的狀態,只有插了插頭時才會去獲取,這個時候就處于熱(Hot)的狀態

17:UI擴展

 UIAlertView *alertView =[[UIAlertView alloc]initWithTitle:@"" message:@"" delegate:nil cancelButtonTitle:@"A" otherButtonTitles:@"B",@"C", nil];    [[alertView rac_buttonClickedSignal] subscribeNext:^(id x) {        NSLog(@"%@",x);    }];    [alertView show];

RAC在很多UI控件里已經擴展出一些可以用的內容,例如上面的代碼;

 

 

一張不錯的RAC類圖:

 

不錯的文章推薦:

這樣好用的ReactiveCocoa,根本停不下來  http://www.cocoachina.com/ios/20150817/13071.html

ReactiveCocoa基本組件:深入淺出RACCommand  http://www.tuicool.com/articles/nYJRvu

ReactiveCocoa 和 MVVM 入門  http://www.cocoachina.com/ios/20150526/11930.html

ReactiveCocoa自述:工作原理和應用  http://www.cocoachina.com/ios/20150702/12302.html

RACSignal的巧克力工廠 http://www.companysz.com/sunnyxx/p/3547763.html

ReactiveCocoa一些概念講解  http://www.thinksaas.cn/group/topic/347067/

細說ReactiveCocoa的冷信號與熱信號(二):為什么要區分冷熱信號  http://www.tuicool.com/articles/e2uMzyq

細說ReactiveCocoa的冷信號與熱信號(三):怎么處理冷信號與熱信號  http://www.tuicool.com/articles/emIVZjY


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 久久网站免费 | 免费在线观看成人av | 中文字幕亚洲一区二区三区 | 成人三级视频网站 | 视频一区二区三区免费观看 | 久久久久国产一区二区三区不卡 | 久久国语对白 | 4p嗯啊巨肉寝室调教男男视频 | 欧美日韩高清一区二区三区 | 日本aaaa片毛片免费观蜜桃 | 免费的性生活视频 | 亚洲国产高清一区 | 在线成人免费观看 | 成人一级在线 | 久久亚洲线观看视频 | 国产乱淫av一区二区三区 | 91不雅视频 | 麻豆视频观看 | 日韩视频―中文字幕 | 国产伦乱视频 | 久久久国产视频 | 精品一区二区三区网站 | 免费在线观看国产精品 | 黄污免费网站 | 国产成人综合在线 | 91精品国产99久久久久久 | 在线播放av网址 | 亚洲欧美成aⅴ人在线观看 av免费在线播放 | 国产精品久久久久久久久久久久久久久久 | 在线观看av国产一区二区 | 久久人人爽人人爽人人片av高清 | 成年片在线观看 | 欧美精品一区自拍a毛片在线视频 | 涩涩99| 黄色免费不卡视频 | 永久免费黄色大片 | 一级色毛片 | 欧美精品a∨在线观看不卡 午夜精品影院 | 欧美成人一二三区 | 黄色网址在线播放 | 日韩精品中文字幕一区二区 |