Functional Reactive Programming(函數響應式(反應式)編程,如下簡稱FRP)是一種響應變化的編程範式,它能經過一種信號機制來記錄值的變化,信號能夠被疊加、分割或合併,經過對信號的組合,就能夠對值進行監聽,有點像數學中的各類公式。例如:git
f(x) = x^2 + 2x + 1;github
每當x變化時,f(x)的值也隨之變化,能夠看出,這個函數是由一個基本函數構成的,即:編程
f(x) = f1(x)^2;
f1(x) = x + 1;數組
數學中有個結論,大體的意思就是大部分的函數,不管多複雜,都能由可列個基本函數構成。簡單說來,計算f(x)的過程就是先計算f1(x)的值,再帶入f(x)中計算,這個計算過程就是FRP中的核心之一,事件流(Stream)。每當x發生變化時,f(x)的值理應響應這種變化,這是FRP的另一個核心:屬性(Properties)。異步
ReactiveCocoa是Github的一個開源的項目,是IOS平臺上對FRP的實現。函數
RACStream就對應FRP中的事件流,一個RACStream對象的意義至關於上面的f1(x)(每個基本函數都有一個與之對應的RACStream對象),最後組合出來的函數f(x)則由RACStreamComponent表示。一個RACStream對象應有幾個基本要素:spa
信號,ReactiveCocoa中的核心,是一個主動信號流,它表示將來將要發送的數據,也能夠將它當作一個「事件轉發器」。一個signal和一個數據源綁定,當數據源的數據有更新時,signal會向signal全部的subscriber(訂閱者)發送事件。線程
Signal只會向subscriber發送三種類型的事件:code
一個Signal的生命週期內能夠接受任意多個Next事件,一個Error事件或者是Completed事件(兩種事件只可能出現一種)。對象
最有意思的是,Signals之間可以進行各類組合,具體說來,它能夠被修改(Map)、過濾(Filter)、疊加(Combine)和串聯(Chain)。
1 [[self.textField.rac_textSignal filter:^BOOL(NSString*value) {
2 return [value length]>= 3; 3 }] subscribeNext:^(NSString*value) { 4 NSLog(@"Text field has been updated: %@", value); 5 >}];
textField的text改變時發出的signal會先被進行過濾,只有當text的長度大於等於3時,纔會被髮到下一個接收方繼續執行。
1 RAC(self,login.enabled) = 2 [RACSignal combineLatest:@[_userName.rac_textSignal, 3 _password.rac_textSignal] 4 reduce:^(NSString *userName, NSString *password){ 5 return @(userName.length > 0 && password.length > 0); 6 }];
userName和password的text改變的signal被聯合在了一塊兒,只有當兩個text的長度都大於0時,login按鈕的enable才爲YES。
subscriber(訂閱者),接受signal發出的事件(next,complete,error)
@weakify(self); RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber){ @strongify(self); [self doSomethingWithSuccessHandler:^{ [subscriber sendNext:nil]; }]; return nil; }]; [aSignal subscribeNext:^(id x){ NSLog(@"next event sended"); }];
@weakify和@strongify的成對使用是確保在block中引用self不會引發循環引用的問題,這是RAC中定義的宏。
creatSignal函數建立了一個Signal,並定義了每次signal被訂閱時須要作的事:doSomethingWithSuccessHandler:,這是一個異步的操做,當操做成功完成時,執行[subscriber sendNext:];告訴每個訂閱者,執行下一步操做。
注意,若是沒有下面一句[aSignal subscribeNext:],則aSignal只會被建立,可是不執行block中的內容(doSomethingWithSuccessHandler:),這時signal沒有一個訂閱者,通常稱之爲冷信號(Cold)。而只有當一個Signal被訂閱了之後([aSignal subscribeNext:]),纔會執行block中的內容,這時signal有了一個訂閱者,它會變成熱信號(Hot),會執行creatSignal:後的block。當block中的內容執行到[subsriber sendNext:]時,全部的subscriber就會執行下一步的操做([aSignal subscribeNext:]後的block)。
反作用,一個信號(RACSignal)每添加一個訂閱者(有一個對象執行[aSignal subscribeNext:]),creatSignal後的block就會被執行一次,這或許是你想要的,或許不是,能夠寫成[[RACSignal creatSignal:...] replay];避免屢次執行creatSignal的block
RACScheduler是ReactiveCocoa中對線程的簡單封裝,事件能夠在指定的scheduler上分發執行,默認狀況是事件都在一個默認的後臺線程裏面執行,如遇特殊狀況須要在主線程調用,使用 deliverOn:可切換線程。
(未完待續...)