2017-08-16 32 views
0

我有一種情況,我想將事件從一個特定的原點信號分成兩個信號,一個立即發射事件,另一個發射事件延遲3秒。其他原始事件總是立即發出新事件。 但是,如果在事件發生之前新事件到達原點信號,則應放棄延遲事件。如何通過使用ReactiveCocoa來滿足這種情況

像這樣 enter image description here

我映射每個原點信號CS1(對於立即發出的事件),並且原點信號的特定事件過濾到CS2(用於延遲發出的事件)enter image description here enter image description here

然後我合併CS1CS2CS3,不會丟棄S2

所以,我的問題是如何放棄或取消S2,以及如何使用RAC而不使用額外的臨時變量來實現這種情況?

ReactiveCocoa 2.x的當前代碼

RACSignal* origin = …  
RACSignal* CS1 = [origin map:^id _Nullable(id _Nullable value) { 
     return @(YES); 
    }]; 
RACSignal* CS2 = [[[origin filter:^BOOL(id _Nullable value) { 
     return [RACSignal empty]; 
    }] delay:3] map:^id _Nullable(id _Nullable value) { 
     return @(NO); 
    }]; 
RACSignal* CS3 = [RACSignal merge:@[CS1, CS2]]; 

回答

1

一個備註無關的實際問題:filter應該返回一個布爾值是YES如果元素應該被髮送和NO如果該元素應該被過濾掉。

要實際的問題:

的解決問題的方法是使用takeUntil。但是,如果您直接將takeUntil應用於CS2,則一旦CS1發生事件,CS2將作爲一個整體取消。

解決方法是使用flatMap爲延遲元素構建新的RACSignal,然後在該內部信號上使用takeUntil

我拆單步入僅僅是爲了清楚多個臨時信號(我也改變了mapfilter,所以我可以看得更清楚發生了什麼嘗試我的例子時,你應該能夠輕鬆地使用你的正確功能有):

RACSignal* CS1 = [self.origin map:^id _Nullable(NSNumber * _Nullable value) { 
    return value; 
}]; 

RACSignal *filtered = [self.origin filter:^BOOL(NSNumber * _Nullable value) { 
    return (value.integerValue % 2) == 0; 
}]; 

RACSignal *delayed = [filtered flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) { 
    // Build a new signal that returns just this one value, 
    // but delayed and only if no event arrives on CS1 
    return [[[RACSignal return:value] 
      delay:3] 
      takeUntil:CS1]; 
}]; 

RACSignal* CS2 = [delayed map:^id _Nullable(NSNumber * _Nullable value) { 
    return @(-value.integerValue); 
}] ; 


RACSignal* CS3 = [RACSignal merge:@[CS1, CS2]]; 

您可以輕鬆地摺疊此回只有兩個信號

RACSignal *CS2 = [[[self.origin filter:^BOOL(NSNumber * _Nullable value) { 
    return (value.integerValue % 2) == 0; 
}] flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) { 
    // Build a new signal that returns just this one value, 
    // but delayed and only if no event arrives on CS1 before 
    return [[[RACSignal return:value] 
      delay:3] 
      takeUntil:CS1]; 
}] map:^id _Nullable(NSNumber * _Nullable value) { 
    return @(-value.integerValue); 
}]; 

我創建a sample project on github來演示解決方案。

+0

非常感謝。這是非常令人印象深刻的答案。我找到了另一個解決方案(CS2返回信號,然後switchToLatest),但它只是丟棄信號,映射塊總是處理。你的答案更加優雅和優化。 – Tepmnthar

+0

似乎CS2永遠不會觸發@MeXx – Tepmnthar

+0

不是嗎?我構建了一個小樣本應用程序,通過按鈕在'origin'上發送值,並且在該示例中工作。也許你可以展示你的用例的更大圖片? – MeXx