【问题标题】:Handling next, completed and error in ReactiveCocoa在 ReactiveCocoa 中处理下一个、完成和错误
【发布时间】:2014-10-15 13:31:39
【问题描述】:

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

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

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

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

还有代码。

1(视图控制器):

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

2(视图模型):

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(视图控制器):

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

【问题讨论】:

    标签: ios objective-c reactive-cocoa


    【解决方案1】:

    按照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,以显示内部值并避免内部订阅。您可能还会看到在其他RACCommand 示例中使用-flatten-switchToLatest,但是只要命令将其allowsConcurrentExecution 属性设置为NO(这是默认值),那么执行会连续发生,从而使-concat自然匹配并表达这些串行语义的运算符。应用-flatten-switchToLatest 实际上会起作用,因为它们在应用于串行信号时会退化为-concat,但它们向读者表达了不适用的语义。

    【讨论】:

    • 感谢您的回答。我同意您提供的方法,这与我最终得到的方法非常相似。您对为什么使用 concat 而不是 flatten 的解释非常有用!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    相关资源
    最近更新 更多