ReactiveCocoa - 将副作用改变为信号

时间:2014-01-09 21:56:40

标签: ios objective-c reactive-cocoa

在我的应用程序中,我有一个信号,它通过flattenMap触发一些异步网络活动。我想在网络活动进行时显示加载指示符。

我目前的解决方案很好用:

  [[[[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属性。

这可能吗?

在我的应用程序的其他地方,我有更复杂的要求,其中元素的可见性取决于几个不同的“事件”,能够通过信号组合这些将更好。

3 个答案:

答案 0 :(得分: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];

答案 1 :(得分: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];

答案 2 :(得分:2)

answer from Josh帮助了很多,但最后我找到了一个更简单的解决方案。简单地将管道分成两个信号,一个用于按下按钮,另一个用于后续的异步活动。然后我合并了两个以给出一个信号,我曾经将其绑定到loadingIndicator的{​​{1}}属性:

hidden