反应性 Cocoa:操作链中的 switchToLatest 有问题

Reactive Cocoa: trouble with switchToLatest in chain of operations

我在处理链式操作列表中的一个操作时遇到问题。我正在尝试使用 Reactive Cocoa 在用户登录并授予对位置服务的访问权限时提供位置流。

我对响应式 Cocoa 和一般的函数式响应式编程的世界还是很陌生,但这是我目前所了解的:

@weakify(self);

// signal of BOOL
RACSignal *loggedInSignal = [[self loggedInSignal] distinctUntilChanged];

// signal of CLAuthorizationStatus
RACSignal *currentStateSignal = [[self currentAuthorizationSignal] distinctUntilChanged];

// defer creation of the location stream signal until subscribed to
RACSignal *locationSignal = [RACSignal defer:^RACSignal *
{
    @strongify(self);
    // To get an uninterrupted stream of locations, just retry the stream if an error occurs
    return [[self locationsSignal] retry];
}];

RACSignal *locationServicesDisabledSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
{
    @strongify(self);
    [self locationServicesDisabled];
    [subscriber sendCompleted];
    return nil;
}];

self.disposable = [[[[[[loggedInSignal map:^id(NSNumber *loggedIn)
{
    return [loggedIn boolValue] ? currentStateSignal : [RACSignal empty];
}]
switchToLatest]
map:^id(NSNumber *currentStatus)
{
    if (CLAuthorizationStatusCanBeginMonitoring([currentStatus intValue]))
    {
        return locationSignal;
    }
    return locationServicesDisabledSignal;
}]
switchToLatest]
subscribeNext:^(CLLocation *location)
{
    @strongify(self);

    CLLocationCoordinate2D coord = location.coordinate;
    [self.output receivedNewLocationWithLatitude:coord.latitude
                                       longitude:coord.longitude
                                        accuracy:location.horizontalAccuracy
                                       timestamp:location.timestamp];
}]
asScopedDisposable];

当授权状态发生变化时,这会按预期工作,starting/stopping 位置流。但是当注销时,位置流继续提供位置。就好像 authStateSignal 没有被处理掉,调整授权状态仍然会 start/stop 流,即使 loggedInSignal 已经返回 NO 作为它的最后一个值。

我试过这个:

(previous code as above)...

    return locationServicesDisabledSignal;
}]
switchToLatest]
takeUntil:[loggedInSignal skip:1]]
subscribeNext:^(CLLocation *location)
{
(etc)...

在第二个 switchToLatest 之后,在下一个日志 in/out 之后停止该信号,但除了感觉有点 "hack-ish" 之外,它在 1 个日志 [=34] 之后停止了位置流事件=],永远不会再启动它们。处理这种情况的正确方法是什么?

还有,感觉我用错了locationServicesDisabledSignal。我希望在 authStateSignal returns 指示位置服务被禁用的状态时调用一个方法,以便我可以做出相应的反应,但是将方法调用放在 [RACSignal createSignal:] 块中不会这样感觉非常 Reactive Cocoa-ey。关于如何使用 Reactive Cocoa 方式进行任何操作的任何其他提示也将不胜感激。

它不适合您的原因是,当您 return 时,[RACSignal empty]; 值将不会通过您的链传播,因为 [RACSignal empty]; 不会发送任何下一个事件。所以试试这个:

 // signal of BOOL
RACSignal *loggedInSignal = [[self loggedInSignal] distinctUntilChanged];

// signal of CLAuthorizationStatus
RACSignal *currentStateSignal = [[self currentAuthorizationSignal] distinctUntilChanged];

// defer creation of the location stream signal until subscribed to
RACSignal *locationSignal = [RACSignal defer:^RACSignal *
{
    @strongify(self);
    // To get an uninterrupted stream of locations, just retry the stream if an error occurs
    return [[self locationsSignal] retry];
}];

RACSignal *locationServicesDisabledSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
{
    @strongify(self);
    [self locationServicesDisabled];
    [subscriber sendCompleted];
    return nil;
}];



self.disposable = [[[RACSignal combineLatest:@[loggedInSignal, currentStateSignal]] flattenMap: ^RACStream * (RACTuple *tuple){
    NSNumber* loggedIn = [tuple first];
    NSNumber* currentStatus = [tuple second];
    if([loggedIn boolValue] && CLAuthorizationStatusCanBeginMonitoring([currentStatus intValue])){
        return locationSignal
    }
    else {
        return locationServicesDisabledSignal
    }
} ]
subscribeNext:^(CLLocation *location)
{
@strongify(self);

CLLocationCoordinate2D coord = location.coordinate;
[self.output receivedNewLocationWithLatitude:coord.latitude
                                   longitude:coord.longitude
                                    accuracy:location.horizontalAccuracy
                                   timestamp:location.timestamp];
}]