Reactive Cocoa - 将某些信号值转换为错误或已完成

时间:2022-05-08 08:08:14

Perhaps I'm still struggling on the reactive learning curve but I am having a hard time figuring out how to bridge a non reactive class with the rest of my reactive code. I am using a category to extend the non-reactive class.

也许我仍然在反应性学习曲线上挣扎,但我很难弄清楚如何将非反应类与其他反应代码联系起来。我正在使用一个类别来扩展非反应类。

The property is just an Enum representing the current state of a network action, states like New, Submitted, Processing and Completed. Right now I have written the following method in my category:

该属性只是一个Enum,表示网络操作的当前状态,如New,Submitted,Processing和Completed。现在我在我的类别中写了以下方法:

@implementation JRequestBase (RACExtensions)
- (RACSignal*) rac_RequestStateSignal
{
    return  RACAble(self, state);
}
@end

However, when state transitions from Processing -> Completed or from any state to Errored I want this signal to send Completed or Error instead of Next Value. How can I accomplish this in a category? I want to do something like:

但是,当状态从Processing - > Completed或从任何状态转换为Errored时,我希望此信号发送Completed或Error而不是Next Value。如何在类别中完成此操作?我想做的事情如下:

@implementation JRequestBase (RACExtensions)
- (RACSignal*) rac_RequestStateSignal
{
    return  [RACAble(self, state) map:^(NSNumber *state){
                 if ([state intValue] == iRequestStateComplete)
                 {    
                     # SEND COMPLETE
                 }
                 else if ([state intValue] == iRequestStateErrored)
                 { 
                     # SEND ERROR
                 }
                 else
                 { 
                     return state;
                 }
            }];
}
@end

edit: I took a look at the GHAPIDemo and have come up with the following:

编辑:我看了看GHAPIDemo并提出了以下内容:

- (RACSignal*) rac_RequestSignal
{
    RACSubject *subject = [[RACReplaySubject alloc] init];
    [[RACAble(self, state) subscribeNext:^(NSNumber* s){
        if ( [s intValue] == JRequestStateCompleted)
        {
            [subject sendNext:self];
            [subject sendCompleted];
        }
        else if ([s intValue] == JRequestStateErrored)
        {
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            // .. Set up dict with necessary values.
            NSError *error = [NSError errorWithDomain:@"blah" code:1 userInfo:dict];

            [subject sendError:error];
        }
    }];
    return subject;
}

I'm not 100% sure this is the right way but it seems to be working.

我不是百分百肯定这是正确的方式,但似乎有效。

1 个解决方案

#1


11  

Whenever you want to map values → signal events, instead of values → values, you should use -flattenMap: to return a signal corresponding to each input value. Then, as the "flatten" in the name implies, they'll be combined into one resulting signal.

无论何时想要映射值→信号事件而不是值→值,都应该使用-flattenMap:来返回与每个输入值对应的信号。然后,正如名称中的“展平”所暗示的那样,它们将被合并为一个结果信号。

However, this case is a little different, because you want to terminate the signal as soon as you get the Complete value. We'll use -takeUntilBlock: to represent that part.

但是,这种情况稍有不同,因为您希望在获得完整值后立即终止信号。我们将使用-takeUntilBlock:来表示该部分。

The resulting code looks something like this:

生成的代码如下所示:

- (RACSignal*) rac_RequestStateSignal
{
    return [[RACObserve(self, state)
        takeUntilBlock:^ BOOL (NSNumber *state){
            return [state intValue] == iRequestStateComplete;
        }]
        flattenMap:^(NSNumber *state){
            if ([state intValue] == iRequestStateErrored)
            { 
                // Create a meaningful NSError here if you can.
                return [RACSignal error:nil];
            }
            else
            { 
                return [RACSignal return:state];
            }
        }];
}

(I used RACObserve because ReactiveCocoa 2.0 is now the only supported version, but you can use RACAble until you're ready to upgrade.)

(我使用了RACObserve,因为ReactiveCocoa 2.0现在是唯一受支持的版本,但在准备升级之前,您可以使用RACAble。)

As a general rule, you should avoid using subjects when possible, since they make code more stateful and reduce laziness.

作为一般规则,您应该尽可能避免使用主题,因为它们使代码更有状态并减少懒惰。

#1


11  

Whenever you want to map values → signal events, instead of values → values, you should use -flattenMap: to return a signal corresponding to each input value. Then, as the "flatten" in the name implies, they'll be combined into one resulting signal.

无论何时想要映射值→信号事件而不是值→值,都应该使用-flattenMap:来返回与每个输入值对应的信号。然后,正如名称中的“展平”所暗示的那样,它们将被合并为一个结果信号。

However, this case is a little different, because you want to terminate the signal as soon as you get the Complete value. We'll use -takeUntilBlock: to represent that part.

但是,这种情况稍有不同,因为您希望在获得完整值后立即终止信号。我们将使用-takeUntilBlock:来表示该部分。

The resulting code looks something like this:

生成的代码如下所示:

- (RACSignal*) rac_RequestStateSignal
{
    return [[RACObserve(self, state)
        takeUntilBlock:^ BOOL (NSNumber *state){
            return [state intValue] == iRequestStateComplete;
        }]
        flattenMap:^(NSNumber *state){
            if ([state intValue] == iRequestStateErrored)
            { 
                // Create a meaningful NSError here if you can.
                return [RACSignal error:nil];
            }
            else
            { 
                return [RACSignal return:state];
            }
        }];
}

(I used RACObserve because ReactiveCocoa 2.0 is now the only supported version, but you can use RACAble until you're ready to upgrade.)

(我使用了RACObserve,因为ReactiveCocoa 2.0现在是唯一受支持的版本,但在准备升级之前,您可以使用RACAble。)

As a general rule, you should avoid using subjects when possible, since they make code more stateful and reduce laziness.

作为一般规则,您应该尽可能避免使用主题,因为它们使代码更有状态并减少懒惰。