我尝试使用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”但它不再起作用。我想知道原因以及如何解决它。谢谢!
答案 0 :(得分: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
的变体 - 它会在将错误传播到外部之前重试2次。此外,doError
用于在发生错误时执行日志记录调用作为副作用(注意:这必须是之前 retry
运算符)
鉴于signInSignal
或userInfoSignal
将在100%的时间内产生错误,按3次按钮将产生以下输出
内部错误
内部错误
内部错误
错误
我建议你看一下另一个解决方案是将逻辑封装到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
的一大好处是,它会在命令运行时自动禁用按钮,因此,如果您的signInSignal
和userInfoSignal
需要一些时间,那么按钮将是在此期间自动禁用,以便用户在其已经运行时无法再次启动该操作。