2014-01-09 68 views
4

在我的應用程序中,我有一個信號通過flattenMap觸發一些異步網絡活動。我想在網絡活動正在進行時顯示加載指示器。ReactiveCocoa - 將副作用變爲信號

我目前的解決方案非常有效:

[[[[self.signInButton 
    rac_signalForControlEvents:UIControlEventTouchUpInside] 
    doNext:^(id x) { 
     // show the loading indicator as a side-effect 
     self.loadingIndicator.hidden = NO; 
    }] 
    flattenMap:^id(id x) { 
     return [self doSomethingAsync]; 
    }] 
    subscribeNext:^(NSNumber *result) { 
     // hide the indicator again 
     self.loadingIndicator.hidden = YES; 
     // do something with the results 
    }]; 

這工作,但我想改變上面的代碼,使負載指示的hidden屬性可以通過一個信號設置。

這可能嗎?

在我的應用程序的其他地方,我有更復雜的要求,其中一個元素的可見性取決於幾個不同的'事件',能夠通過信號組成這些會更好。

回答

13

RACCommand是量身打造的正是這種使用情況下,通常會導致較大幅度簡單的代碼替代品:

@weakify(self); 

RACCommand *signInCommand = [[RACCommand alloc] initWithSignalBlock:^(id _) { 
    @strongify(self); 
    return [self doSomethingAsync]; 
}]; 

self.signInButton.rac_command = signInCommand; 

// Show the loading indicator while signing in. 
RAC(self.loadingIndicator, hidden) = [signInCommand.executing not]; 
2

它看起來像你的信號是:當signInButtonSignalresultSignal發送一個值,反轉最後一個值hidden。這很簡單。

[[[hiddenSig replayLast] not] sample:[RACSignal merge:@[signInButtonSignal, resultSignal]]; 

我正好使用與您的情況類似的構造。這可能是好的,把它包成一個操作:

- (RACSignal *)toggle:(RACSignal *)toggler 
{ 
    return [[[self replayLast] not] sample:toggler]; 
} 

那你剛纔

[hiddenSig toggle:[RACSignal merge:@[signInButtonSignal, resultSignal]]]; 

另一種可能性是一個類的方法,追平了狀態的映射塊:

+ (RACSignal *)toggle:(RACSignal *)toggler initially:(BOOL)initial 
{ 
    __block BOOL currVal = initial; 
    return [[toggler map:^id (id _) { 
     currVal = !currVal; 
     return @(currVal); 
    }] startWith:@(initial)]; 
} 

然後

[RACSignal toggle:[RACSignal merge:@[signInButtonSignal, resultSignal]] 
     initially:NO]; 
+0

+1謝謝你 - 我會盡量把你的答案包起來,並儘快給它試一試。非常感激。 – ColinE

+0

你打賭!我很高興你復活這個問題。我有一天看到了它,但是在我能夠回答之前就刪除了它。 –

+0

我刪除它,因爲我*認爲*我已經找到了答案,在github上看到這個問題https://github.com/ReactiveCocoa/ReactiveCocoa/issues/469然而,與RC2.0在答案中描述的一些技術是不再可用。從1.0-2.0的突破性廣泛變化可能會使RC RC學習變得有些棘手......並且在RC3.0中,他們計劃繼續進行一些進一步的重大突破性變革。無論如何 - 這是一個非常棒的框架。 – ColinE

2

answer from Josh幫助了很多,但最終我找到了一個更簡單的解決方案。只需將管道分成兩個信號,一個用於按鈕按下,另一個用於隨後的異步活動。然後我合併兩個給我用它綁定到loadingIndicatorhidden財產的信號:

// a signal that triggers sign-in 
RACSignal *signInStartSignal = [self.signInButton 
         rac_signalForControlEvents:UIControlEventTouchUpInside]; 

// a signal that emits the sign in result 
RACSignal *signInResultSignal = 
    [signInStartSignal 
    flattenMap:^id(id x) { 
     return [self doSomethingAsync]; 
    }]; 

[signInResultSignal 
    subscribeNext:^(NSNumber *result) { 
    // do something based on the result 
    }]; 

// merge the two signals 
RACSignal *signInInProgress = 
    [[RACSignal merge:@[signInResultSignal, signInStartSignal]] 
    map:^id(id value) { 
     // if the signal value is a UIButton, the signal that 
     // just fired was the signInStartSignal 
     return @(![[value class] isSubclassOfClass:[UIButton class]]); 
    }]; 

RAC(self.signInFailureText,hidden) = signInInProgress; 
+0

合併但區分兩個信號並將值映射到布爾值! _Nice_解決方案。非常好。 –

+0

謝謝,很高興你喜歡它:-) – ColinE

相關問題