【问题标题】:Error block not called while using ReactiveCocoa使用 ReactiveCocoa 时未调用错误块
【发布时间】:2013-11-08 00:57:56
【问题描述】:

由于某种原因,我没有收到错误消息。 (我已经简化了这里的代码以直截了当。)

// Send an error message 
_loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendError:error]; // Pretend this is a real error
        return nil;
    }];
}];

// Subscribe to loginButton's returned signal
[_loginButton.rac_command.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    [loginSignal subscribeError:^(NSError *error) {
         NSLog(@"A");
    } completed:^{
         NSLog(@"B");
    }];
}];

这将打印“B”。知道为什么吗?如果在订阅者上调用-sendError:,为什么完成块会收到它?

【问题讨论】:

    标签: ios objective-c reactive-cocoa


    【解决方案1】:

    如您所见,RACCommand 会自动捕获 executionSignals 中的错误。

    这旨在为-flatten-concat-switchToLatest 等运算符提供便利,否则如果任何内部信号发生错误,它们将过早终止。

    如果您只关心知道何时发生错误,您应该改用RACCommand.errors。如果您想知道错误的来源,检查错误域和代码可能比订阅每个内部信号的error 事件更容易(或者至少更直观)。

    Subscriptions-within-subscriptions,甚至subscriptions in general,都是 RAC 中的代码异味。即使您不想使用errors,通常也有更高级别的运算符来完成您想要的操作(例如使用-map:-catch: 应用于每个内部信号)。

    【讨论】:

    • 谢谢!所以,让我们假设性地说,我想执行一个给我一个对象的网络操作,然后执行第二个网络操作来修改数据库中该对象的一些属性。我想捕捉错误并在第一个操作中显示它们。订阅是可行的,但它很臭?而且我最好使用地图和捕获的组合?
    • @drhr 在这种情况下,我认为最好将第二个操作包含在命令的信号块中。如果它总是作为该命令的一部分运行,它基于通过该命令的值,并通知该命令的状态,看起来它在逻辑上也属于那里。
    • 感谢您的想法,我会尝试一下。因此,如果我想将各种 rac_commands 的独特功能合并到一个通用的最终信号中(用于处理返回相同信息的不同类型的登录方法),我可以先实例化一个 RACSignal,然后附加一些“处理程序”方法(map、catch 或臭订阅),并让每个RACCommand 输入那个信号? (顺便说一句 - 非常酷的库,它真的动摇了我的命令式 / OOP 思维方式..)
    • @drhr 嗯,不看具体的代码示例很难知道。我的直觉会说您可能想要合并所有命令的结果,以从所有命令中创建一个组合信号,但这是一项相当棘手的任务。不幸的是,RACCommand 通常相当不直观,所以我们希望在 3.0 中用更简单的模式来简化/替换它。
    【解决方案2】:

    这似乎基于this suggestion 起作用(将其物化和非物化)。

    // Send an error message 
    _loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendError:error]; // Pretend this is a real error
            return nil;
        }] materialize];
    }];
    
    // Subscribe to loginButton's returned signal
    [_loginButton.rac_command.executionSignals subscribeNext:^(RACSignal *loginSignal) {
        [[loginSignal dematerialize] subscribeError:^(NSError *error) {
             NSLog(@"A");
        } completed:^{
             NSLog(@"B");
        }];
    }];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      • 2020-01-16
      • 1970-01-01
      相关资源
      最近更新 更多