反应性 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];
}]
我在处理链式操作列表中的一个操作时遇到问题。我正在尝试使用 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];
}]