【问题标题】:ReactiveCocoa -- When error is catched the signal can not be triggered againReactiveCocoa -- 当错误被捕获时,信号不能被再次触发
【发布时间】:2018-02-06 06:45:01
【问题描述】:

我尝试用 ReactiveCocoa 序列化几个异步网络:

[[[[self.profileView.signInButton rac_signalForControlEvents:UIControlEventTouchUpInside] flattenMap:^__kindof RACSignal * _Nullable(__kindof UIControl * _Nullable value) {
    @strongify(self)
    return [self.viewModel signInSignal];
}] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
    return [self.viewModel userInfoSignal];
}] subscribeNext:^(id  _Nullable x) {

} error:^(NSError * _Nullable error) {
    NSLog(@"error");
}];

如果没有发生网络错误,它就可以工作。但是,当发生任何错误并调用错误块时,我再次单击“signInButton”,但它不再起作用。我想知道原因以及如何解决它。谢谢!

【问题讨论】:

    标签: objective-c io reactive-cocoa


    【解决方案1】:

    原因是Error 事件会立即通过运算符链转发,而Error 事件会终止订阅。

    解决此问题的一种方法是使用retry 运算符,该运算符在发生错误时重新订阅信号。下面是使用 retry 的示例的修改版本:

    @weakify(self);
    [[[[[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] flattenMap:^__kindof RACSignal * _Nullable(__kindof UIControl * _Nullable value) {
      @strongify(self)
      return [self.viewModel signInSignal];
    }] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
      return [self.viewModel userInfoSignal];
    }] doError:^(NSError * _Nonnull error) {
      NSLog(@"Inner Error: %@", error);
    }] retry:2]
     subscribeNext:^(id  _Nullable x) {
      NSLog(@"Next: %@", x);
    } error:^(NSError * _Nullable error) {
      NSLog(@"Error: %@", error);
    }];
    

    这里使用了带有retryCount 的变体——它会在将错误传播到外部之前重试两次。此外,doError 用于在发生错误时执行日志调用作为副作用(注意:这必须在retry 运算符之前

    鉴于signInSignaluserInfoSignal 100% 的时间会产生错误,3 次按钮按下将产生以下输出

    内部错误

    内部错误

    内部错误

    错误

    RAC 命令

    我建议您查看的另一个解决方案是将逻辑封装到 RACCommand(在您的 viewModel 中):

    _signInCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
      return [self.signInSignal flattenMap:^RACSignal *(id value) {
        return self.userInfoSignal;
      }];
    }];
    

    您可以将其链接到您的按钮,如下所示:

    self.button.rac_command = self.viewModel.signInCommand;
    

    这样,你就不需要手动处理重试了:每次点击按钮都会调用一次命令,可以成功完成也可以出错。

    您可以通过命令特殊信号处理命令的副作用:

    [[self.viewModel.signInCommand errors] subscribeNext:^(NSError * _Nullable x) {
      NSLog(@"Error: %@", x);
    }];
    
    [self.viewModel.signInCommand.executionSignals subscribeNext:^(id  _Nullable signal) {
      [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"Next: %@", x);
      }];
    }];
    

    以这种方式使用RACCommand 的一大好处是它会在命令运行时自动禁用按钮,因此如果您的signInSignaluserInfoSignal 需要一些时间,按钮将同时自动禁用所以用户无法在该操作已经运行时再次启动该操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多