Reactive Cocoa 中的超时实现是否正确?
Is this implementation of a timeout in Reactive Cocoa correct?
我做了一个连接到 ReactiveCocoa 中的按钮的登录。即使我测试了这段代码,它似乎可以正常工作,但我不确定我是否做对了。
成功时登录信号 returns "next",其他情况下登录信号 "error"。由于我不希望按钮因错误而被取消订阅,因此我使用了 catch 函数。
我想要的是:如果未触发 loginSignal,我希望在 2 秒后触发超时。这是否正确完成?是不是也做对了"reactive way"?
[[[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x) {
[self disableUI];
}]
flattenMap:^(id value) {
return [[[[[self.login loginSignalWithUsername:self.usernameTextField.text
andPassword:self.passwordTextField.text]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(@"ERROR_TITLE", @"Error")
message:NSLocalizedString(@"LOGIN_FAILURE", @"Login not successful.")];
return [RACSignal empty];
}]
deliverOn:[RACScheduler mainThreadScheduler]]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(@"TIMEOUT_TITLE", @"Timeout occured")
message:NSLocalizedString(@"REQUEST_NOT_POSSIBLE", @"Server request failed")];
return [RACSignal empty];
}];
}]
subscribeNext:^(id x) {
[self enableUI];
// Go to next page after login
}];
我认为您应该使用 RACCommand,它是将信号绑定到 UI 的一个很好的集线器:
RACCommand* command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
return [[[self.login loginSignalWithUsername:self.username password:self.password]
doCompleted:^{
// move to next screen
}]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]];
}];
self.button.rac_command = command;
然后您可以使用命令 "errors" 信号处理任何错误(登录或超时):
[[command errors] subscribeNext:^(NSError* err) {
// display error "err" to the user
}];
信号在执行时会自动禁用按钮。如果您需要禁用 UI 的其他部分,您可以使用命令的 "executing" 信号。
[[command executing] subscribeNext:^(NSNumber* executing) {
if([executing boolValue]) {
[self disableUI];
} else {
[self enableUI];
}
}];
// bonus note: if your enableUI method took a BOOL you could lift it in one line :
[self rac_liftSelector:@selector(enableUI:) withSignals:[command executing], nil];
我做了一个连接到 ReactiveCocoa 中的按钮的登录。即使我测试了这段代码,它似乎可以正常工作,但我不确定我是否做对了。 成功时登录信号 returns "next",其他情况下登录信号 "error"。由于我不希望按钮因错误而被取消订阅,因此我使用了 catch 函数。
我想要的是:如果未触发 loginSignal,我希望在 2 秒后触发超时。这是否正确完成?是不是也做对了"reactive way"?
[[[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x) {
[self disableUI];
}]
flattenMap:^(id value) {
return [[[[[self.login loginSignalWithUsername:self.usernameTextField.text
andPassword:self.passwordTextField.text]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(@"ERROR_TITLE", @"Error")
message:NSLocalizedString(@"LOGIN_FAILURE", @"Login not successful.")];
return [RACSignal empty];
}]
deliverOn:[RACScheduler mainThreadScheduler]]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]]
catch:^RACSignal *(NSError *error) {
[self enableUI];
[self showAlertWithTitle:NSLocalizedString(@"TIMEOUT_TITLE", @"Timeout occured")
message:NSLocalizedString(@"REQUEST_NOT_POSSIBLE", @"Server request failed")];
return [RACSignal empty];
}];
}]
subscribeNext:^(id x) {
[self enableUI];
// Go to next page after login
}];
我认为您应该使用 RACCommand,它是将信号绑定到 UI 的一个很好的集线器:
RACCommand* command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
return [[[self.login loginSignalWithUsername:self.username password:self.password]
doCompleted:^{
// move to next screen
}]
timeout:2.0 onScheduler:[RACScheduler mainThreadScheduler]];
}];
self.button.rac_command = command;
然后您可以使用命令 "errors" 信号处理任何错误(登录或超时):
[[command errors] subscribeNext:^(NSError* err) {
// display error "err" to the user
}];
信号在执行时会自动禁用按钮。如果您需要禁用 UI 的其他部分,您可以使用命令的 "executing" 信号。
[[command executing] subscribeNext:^(NSNumber* executing) {
if([executing boolValue]) {
[self disableUI];
} else {
[self enableUI];
}
}];
// bonus note: if your enableUI method took a BOOL you could lift it in one line :
[self rac_liftSelector:@selector(enableUI:) withSignals:[command executing], nil];