ios - 在 ReactiveCocoa 中处理下一步、完成和错误

标签 ios objective-c reactive-cocoa

我在 ReactiveCocoa 的世界里还是个新手,我只是想弄清楚这个常见的场景。我注意到其他人在 GitHub 和 SO 上都在努力解决这个问题,但我仍然没有找到合适的答案。

以下示例确实有效,但我看到 Justin Summers 说订阅中的订阅或一般的订阅可能是代码味道。因此,我想在学习这种新范式时尽量避免坏习惯。

因此,示例(使用 MVVM)非常简单:

  1. ViewController 包含一个登录按钮,该按钮连接到 View 模型中的登录命令
  2. ViewModel 指定命令操作并为此示例模拟一些网络请求。
  3. ViewController 订阅命令的执行信号并能够区分三种类型的返回:下一步、错误和完成。

还有代码。

1( View Controller ):

RAC(self.loginButton, rac_command) = RACObserve(self, viewModel.loginCommand);

2( View 模型):

self.loginCommand = [[RACCommand alloc] initWithEnabled:canLoginSignal 
                        signalBlock:^RACSignal *(id input) {
                            return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                        BOOL success = [username isEqualToString:@"user"] && [password isEqualToString:@"password"];
                        // Doesn't really make any sense to use sendNext here, but lets include it to test whether we can handle it in our viewmodel or viewcontroller
                        [subscriber sendNext:@"test"];
                            if (success) 
                            {
                                [subscriber sendCompleted];
                            } else {
                                [subscriber sendError:nil];
                            }

                        // Cannot cancel request
                        return nil;
                        }] materialize];
                    }];

3( View Controller ):

[self.viewModel.loginCommand.executionSignals subscribeNext:^(RACSignal *execution) {
    [[execution dematerialize] subscribeNext:^(id value) {
        NSLog(@"Value: %@", value);
    } error:^(NSError *error) {
        NSLog(@"Error: %@", error);
    } completed:^{
        NSLog(@"Completed");
    }];
}];

你会如何以一种更像 ReactiveCococa 的方式来做到这一点?

最佳答案

RACCommand 的工作方式,值来自 executionSignals 信号,错误来自 errors 信号,以及完成,嗯,那些是在您的示例中,人们可能会使用 -materialize-dematerialize

在给出的例子中,登录,可以说它不需要完成来建模。相反,可以将登录信号定义为二进制行为:它要么发送 @YES(例如),要么发送错误。在这些条件下,代码将是:

[[self.viewModel.loginCommand.executionSignals concat] subscribeNext:^(id _) {
    // Handle successful login
}];

[self.viewModel.loginCommand.errors subscribeNext:^(NSError *error) {
    // Handle failed login
}];

这显然与 RAC 中典型的 subscribeNext:error:completed: 模式有点不同。这完全是由于 RACCommand 的 API。

请注意,-concat 运算符已应用于 executionSignals 以显示内部值并避免内部订阅。您可能还会看到 -flatten-switchToLatest 在其他 RACCommand 示例中使用,但只要命令有其 allowsConcurrentExecution属性设置为 NO(这是默认值),然后执行顺序发生,使 -concat 成为自然匹配和表达这些串行语义的运算符。应用 -flatten-switchToLatest 实际上会起作用,因为它们在应用于串行信号信号时退化为 -concat,但它们表示对读者来说不适用的语义。

关于ios - 在 ReactiveCocoa 中处理下一步、完成和错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26383918/

相关文章:

objective-c - 拆分 RACSignal 以消除状态

ios - ReactiveCocoa 的 RACObserve 是不是要替换属性的 set 方法?

ios - 检查很多 int 是否相等

objective-c - 当路径正确时,为什么 NSFIleManager -fileExistsAtPath 找不到现有文件?

iphone - ScrollView 中的砌体布局

ios - 将发出数组的 SignalProducer 转换为发出原始数组所有元素的 SignalProducer

ios - 不兼容的操作数类型 ('NSUInteger'(又名 'unsigned long')和 'id _Nullable')

ios - 在 iOS PWA 和 safari 之间共享 IndexedDB

ios - 怎么可能tableView :commitEditingStyle:forRowAtIndexPath: be called with a nil indexPath?

objective-c - 选择 HTML 文本区域时禁用 iPhone 键盘