
今天主要分享內(nèi)容:
- ReactiveCocoa簡(jiǎn)單介紹
- 響應(yīng)式編程和函數(shù)編程的概述
- RACSignal 信號(hào)
- RACSignald訂閱過(guò)程
- First Demo
- Second Demo
- 參考鏈接
ReactiveCocoa
- GitHub mac 客戶端副產(chǎn)物
- FRP(響應(yīng)式函數(shù)編程)在cocoa框架的實(shí)現(xiàn)
- ReactiveCocoa可以對(duì)代理模式, target-action模式,鍵值對(duì)觀察(KVO)等進(jìn)行替代
響應(yīng)式函數(shù)編程概述
ReactiveCocoa框架讓你可以在iOS應(yīng)用中使用響應(yīng)式函數(shù)編程(FRP)
- 命令式編程 VS 函數(shù)式編程 VS 響應(yīng)式編程(粗淺介紹)
int func(int x)
{
int result = 1;
for (int i = 1; i <=x; ++i)
{
result *= i;
}
} ```
命令式編程關(guān)心解決問(wèn)題的步驟
你得把達(dá)到目的的步驟詳細(xì)的描述出來(lái),
然后交給機(jī)器去運(yùn)行。
需要管理非常多的中間狀態(tài)量,代碼繁雜。
int func(int x)
{
if (x == 1) return 1;
return x * func(x - 1);
} ```
函數(shù)式編程關(guān)心數(shù)據(jù)的映射
這里的映射就是數(shù)學(xué)上「函數(shù)」的概念,
一種東西和另一種東西之間的對(duì)應(yīng)關(guān)系。
沒(méi)有狀態(tài)量,簡(jiǎn)潔高效。
void test() {
int a = 5;
int b = 6;
int c = a + b;
int d = funAdd(&a , &b);//a b中的值
a = 10;
NSLog(@"%d",c);
} ```
響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程范式。
在響應(yīng)式編程中d的值會(huì)隨著a或b的更新而更新。
### RACSignal 信號(hào)
ReactiveCocoa四大核心組件構(gòu)成:
信號(hào)源:RACStream 及其子類;
訂閱者:RACSubscriber 的實(shí)現(xiàn)類及其子類;
調(diào)度器:RACScheduler 及其子類;
清潔工:RACDisposable 及其子類。
其中,信號(hào)源又是最核心的部分,其他組件都是圍繞它運(yùn)作的。
ReactiveCocoa使用信號(hào)來(lái)代表異步事件,提供了一種統(tǒng)一的方式來(lái)處理所有異步的行為,包括代理方法、block 回調(diào)、target-action 機(jī)制、通知、KVO 等:
// 代理方法
[[self
rac_signalForSelector:@selector(webViewDidStartLoad:)
fromProtocol:@protocol(UIWebViewDelegate)]
subscribeNext:^(id x) {
// 實(shí)現(xiàn) webViewDidStartLoad: 代理方法
}];
// target-action
[[self.avatarButton
rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(UIButton *avatarButton) {
// avatarButton 被點(diǎn)擊了
}];
// 通知
[[[NSNotificationCenter defaultCenter]
rac_addObserverForName:kReachabilityChangedNotification object:nil]
subscribeNext:^(NSNotification *notification) {
// 收到 kReachabilityChangedNotification 通知
}];
// KVO
[RACObserve(self, username) subscribeNext:^(NSString *username) {
// 用戶名發(fā)生了變化
}];
### RACSignald訂閱過(guò)程
// 創(chuàng)建信號(hào) 并發(fā)送信號(hào)
//使用RACSignal的createSignal:方法創(chuàng)建信號(hào)。描述這個(gè)信號(hào)的block是這個(gè)方法唯一的入?yún)?。?dāng)這個(gè)信號(hào)有訂閱者的時(shí)候,block中的代碼就會(huì)執(zhí)行。
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"dispose");
}];
}];
// 訂閱信號(hào)
RACDisposable *disposable = [signal subscribeNext:^(id x) {
NSLog(@"next value is %@",x);
} error:^(NSError *error) {
NSLog(@"error -> %@",[error description]);
} completed:^{
NSLog(@"It finished success");
}];
[disposable dispose];
//ReactiveCocoa的信號(hào)(表現(xiàn)為RACSignal類)會(huì)向他的訂閱者們發(fā)送事件流。
//發(fā)送的事件分為三種類型:next,error 和 completed。
//一個(gè)信號(hào)在因?yàn)閳?bào)錯(cuò)或完成的終止前可以發(fā)送若干個(gè)事件。
### First Demo
實(shí)現(xiàn)一個(gè)登陸界面

要求:
1. User & Password不少于3位
2. 低于3位顯示紅色,正常顯示藍(lán)色
3. 登錄按鈕只有在用戶名和密碼都有效輸入時(shí)才能使用
Answer 1
//ReactiveCocoa框架使用category為很多標(biāo)準(zhǔn)的UIKit控件添加了信號(hào)
//可以對(duì)它們的各種事件進(jìn)行訂閱
//1.創(chuàng)建信號(hào)
RACSignal *userName = [self.usernameTextField rac_textSignal];
//2.篩選
RACSignal *validUsername = [userName filter:^BOOL(id value) {
NSString *text = value;
return [self isValidUsername:text];
}];
//3.調(diào)用信號(hào)RACSignal的subscribeNext就能訂閱,
//subscribeNext:方法就提供了一個(gè)block,
//在每個(gè)next事件到達(dá)時(shí)執(zhí)行里面的代碼。
[validUsername subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
Answer 2
[[self.usernameTextField.rac_textSignal
map:^id(NSString *username) {
return [self isValidUsername:username] ? [UIColor whiteColor] : [UIColor redColor];
}]
subscribeNext:^(UIColor *color) {
self.usernameTextField.backgroundColor = color;
}];
[[self.passworkTextField.rac_textSignal
map:^id(NSString *password) {
return [self isValidUsername:password] ? [UIColor whiteColor] : [UIColor redColor];
}]
subscribeNext:^(UIColor *color) {
self.passworkTextField.backgroundColor = color;
}];```
Answer 3
//創(chuàng)建兩個(gè)發(fā)送布爾值的信號(hào)validUsernameSignal、validPasswordSignal
//對(duì)用戶名和密碼的輸入進(jìn)行驗(yàn)證。
RACSignal *validUsernameSignal =
[self.usernameTextField.rac_textSignal
map:^id(NSString *text) {
return @([self isValidUsername:text]);
}];
RACSignal *validPasswordSignal =
[self.passworkTextField.rac_textSignal
map:^id(NSString *text) {
return @([self isValidPassword:text]);
}];
//信號(hào)合成
//接下來(lái)的任務(wù)就是合成這兩個(gè)信號(hào),用以共同決定登錄按鈕是否可用
RACSignal *signUpActiveSignal =
[RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]
reduce:^id(NSNumber *usernameValid, NSNumber *passwordValid) {
return @([usernameValid boolValue] && [passwordValid boolValue]);
}];
//上面的代碼使用combineLatest:reduce:方法 (RACSignal合成方法可以合成任意數(shù)量的信號(hào))
//獲取validUsernameSignal和validPasswordSignal的最近一個(gè)信號(hào)值并組合成一個(gè)全新的信號(hào)。
//每當(dāng)兩個(gè)源信號(hào)的其中一個(gè)發(fā)送新值,
//reduce里的block代碼塊就會(huì)執(zhí)行(reduce中 block的入?yún)⒑驮葱盘?hào)一一對(duì)應(yīng))
//其返回的值會(huì)作為合成信號(hào)的值發(fā)送出去。
//最后是訂閱
[signUpActiveSignal subscribeNext:^(NSNumber *signupActive) {
self.signinBnt.enabled = [signupActive boolValue];
}];
Second Demo

1.主動(dòng)獲取數(shù)據(jù)并刷新TableView
2.根據(jù)搜索關(guān)鍵字獲取指定數(shù)據(jù),并刷新TableView;
Demo地址
參考鏈接
Reactive github
美團(tuán)的幾篇博客
RACSignal的Subscription深入分析
raywenderlich 上的文章:
http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1、http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2、http://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1、http://www.raywenderlich.com/74131/mvvm-tutorial-with-reactivecocoa-part-2。