处理ReactiveCocoa中的next,completed和error

时间:2014-10-15 13:31:39

标签: ios objective-c reactive-cocoa

我在ReactiveCocoa世界中仍然相当新,我只想澄清这种常见情况。我注意到其他人在GitHub和SO上都在努力解决这个问题,但我仍然没有找到合适的答案。

以下示例确实有效,但我看到Justin Summers说订阅内订阅或订阅通常可能是代码味道。因此,我想在学习这个新范例时尝试避免坏习惯。

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

  1. ViewController包含一个登录按钮,该按钮连接到viewmodel中的登录命令
  2. ViewModel指定命令操作并模拟此示例的某些网络请求。
  3. ViewController订阅命令的executionSignals,能够区分三种类型的返回:next,error和complete。
  4. 代码。

    1(ViewController):

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

    2(ViewModel):

    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(ViewController):

    [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-kind-a方式做到这一点?

1 个答案:

答案 0 :(得分:8)

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示例中看到-switchToLatestRACCommand,但只要命令将其allowsConcurrentExecution属性设置为NO(这是默认值)然后执行连续发生,使-concat运算符自然匹配并表达那些串行语义。应用-flatten-switchToLatest实际上可行,因为它们在应用于串行信号信号时会退化为-concat,但它们会向不适用的读者表达语义。