天天看點

函數式 響應程式設計

函數式 響應程式設計

ReactiveCocoa的基本使用方法

ReactiveCocoa是github一個開源項目,是在iOS平台上對FRP的實作。FRP的核心是信号,信号在ReactiveCocoa(以下簡稱RAC)中是通過RACSignal來表示的,信号是資料流,可以被綁定和傳遞。

可以把信号想象成水龍頭,隻不過裡面不是水,而是玻璃球(value),直徑跟水管的内徑一樣,這樣就能保證玻璃球是依次排列,不會出現并排的情況(資料都是線性處理的,不會出現并發情況)。水龍頭的開關預設是關的,除非有了接收方(subscriber),才會打開。這樣隻要有新的玻璃球進來,就會自動傳送給接收方。可以在水龍頭上加一個過濾嘴(filter),不符合的不讓通過,也可以加一個改動裝置,把球改變成符合自己的需求(map)。也可以把多個水龍頭合并成一個新的水龍頭(combineLatest:reduce:),這樣隻要其中的一個水龍頭有玻璃球出來,這個新合并的水龍頭就會得到這個球。

RAC統一了對KVO、UI Event、Network request、Async work的處理,因為它們本質上都是值的變化(Values over time)。

替代KVO

<code>@property</code><code>(strong)</code><code>NSString</code> <code>*username;</code>

<code>[RACObserve(</code><code>self</code><code>,username) subscribeNext:^(</code><code>NSString</code> <code>*newName){</code>

<code>    </code><code>NSLog</code><code>(@</code><code>"%@"</code><code>,newName);</code>

<code>}];</code>

隻要username發生變化就列印出來。展現綁定和響應。

<code>[[RACObserver(</code><code>self</code><code>,username) filter:^(</code><code>NSString</code> <code>*newName) {</code>

<code>   </code><code>return</code> <code>[newName hasPrefix:@</code><code>"j"</code><code>];</code>

<code>}] subscribeNext:^(</code><code>NSString</code> <code>*newName) {</code>

<code>   </code><code>NSLog</code><code>(@</code><code>"%@"</code><code>,newName);</code>

<code>}</code>

增加一個過濾器

替代selector

1

2

3

4

<code>self</code><code>.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(</code><code>id</code> <code>_) {</code>

<code>    </code><code>NSLog</code><code>(@</code><code>"button was pressed!"</code><code>);</code>

<code>    </code><code>return</code> <code>[RACSignal empty];</code>

流的實作

5

<code>RAC(</code><code>self</code><code>, timeLabel.text) = [[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] startWith:[</code><code>NSDate</code> <code>date]] map:^</code><code>id</code> <code>(</code><code>NSDate</code> <code>*value) {</code>

<code>   </code><code>NSLog</code><code>(@</code><code>"value:%@"</code><code>, value);</code>

<code>   </code><code>NSDateComponents</code> <code>*dateComponents = [[</code><code>NSCalendar</code> <code>currentCalendar] components:</code><code>NSHourCalendarUnit</code> <code>|</code><code>NSMinuteCalendarUnit</code> <code>| </code><code>NSSecondCalendarUnit</code> <code>fromDate:value];</code>

<code>  </code><code>return</code> <code>[</code><code>NSString</code> <code>stringWithFormat:@</code><code>"%02ld:%02ld:%02ld"</code><code>, (</code><code>long</code><code>)dateComponents.hour, (</code><code>long</code><code>)dateComponents.minute, (</code><code>long</code><code>)dateComponents.second];</code>

  

組合

<code>RAC(</code><code>self</code><code>, submitButton.enabled) = [RACSignal combineLatest:@[</code><code>self</code><code>.usernameField.rac_textSignal, </code><code>self</code><code>.passwordField.rac_textSignal] reduce:^</code><code>id</code> <code>(</code><code>NSString</code> <code>*userName, </code><code>NSString</code> <code>*password) {</code>

<code>  </code><code>return</code> <code>@(userName.length &gt;= 6 &amp;&amp; password.length &gt;= 6);</code>

将usernameField和passwordField的信号綁定在一起做reduce處理。傳回一個BOOL值去跟self.submitButton.enabled進綁定。

網絡請求

<code>self</code><code>.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(</code><code>id</code> <code>sender) {</code>

<code>    </code><code>return</code> <code>[client logIn];</code>

<code>}];&lt;br&gt;&lt;br&gt;[</code><code>self</code><code>.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {&lt;br&gt;  [loginSignal subscribeCompleted:^{&lt;br&gt;    </code><code>NSLog</code><code>(@</code><code>"Logged in successfully!"</code><code>);&lt;br&gt;  }];&lt;br&gt;}];</code>