4

在我的应用程序中,我有一个信号通过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可以通过信号设置加载指示器的属性。

这可能吗?

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

4

3 回答 3

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];
于 2014-01-22T08:51:08.843 回答
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];
于 2014-01-10T08:24:45.643 回答
2

乔希的回答帮助很大,但最后我找到了一个更简单的解决方案。只需将管道分成两个信号,一个用于按钮按下,另一个用于随后的异步活动。然后我将两者合并以给出一个我用来绑定到loadingIndicator'hidden属性的信号:

// 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;
于 2014-01-12T18:47:33.710 回答