#objective-c #reactive-cocoa #frp
#objective-c #реактивный-cocoa #frp
Вопрос:
Хорошо, теперь, когда я знаю, как создать повторную попытку цикла, я застрял на другой проблеме. Я думаю, что знаю, почему, но, похоже, не могу понять, как. В приведенном ниже коде у меня есть последовательность событий, которые будут собирать местоположение. Измените геокодирование и, наконец, сравните его со списком разрешенных кодов стран. Моя текущая проблема заключается в том, что предупреждение с просьбой разрешить службы определения местоположения для приложения будет отображаться, даже если ошибка не была отправлена. Я думаю, это связано с тем, что вызов [self retryWithAlert] будет вызван сразу после настройки последовательности, и я не должен размещать код для создания и отображения предупреждения там, где он находится в данный момент. Но когда я пытаюсь обернуть это в [RACSignal create:] Кажется, я просто не могу понять это правильно. И без дальнейших церемоний, вот код:
Сначала сама последовательность
_locationManager = [[CLLocationManager alloc] init];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
@weakify( self )
[[[[[_locationManager
rac_fetchLocationSignal]
catchTo:[self retryWithAlert]]
flattenMap:^RACStream *( CLLocation *newLocation ) {
@strongify( self )
return [self reverseGeocodeLocation:newLocation];
}]
flattenMap:^RACStream *( NSString *ISOCountryCode ) {
@strongify( self )
return [self checkCountryPermissibleSignal:ISOCountryCode];
}]
subscribeNext:^( id x ) {
[_locationManager stopUpdatingLocation];
NSLog( @"Country is valid!" );
} error:^( NSError *error ) {
NSLog( @"Error: %@", error );
}];
[_locationManager startUpdatingLocation];
И вот код для [self retryWithAlert]
- (RACSignal *)retryWithAlert
{
UIAlertView *retryAlert =
[[UIAlertView alloc] initWithTitle:@"Trouble"
message:@"Make sure location services are enabled and that the app is allowed to use them."
delegate:self
cancelButtonTitle:@"Retry"
otherButtonTitles:nil];
[retryAlert show];
return [[[retryAlert
rac_buttonClickedSignal]
flattenMap:^RACStream *( id value ) {
[_locationManager startUpdatingLocation];
return [_locationManager rac_fetchLocationSignal];
}]
catch:^RACSignal *( NSError *error ) {
return [self retryWithAlert];
}];
}
Ответ №1:
Вы действительно близки. Как вы заметили, проблема в том, что -retryWithAlert
сообщение отправляется немедленно при выполнении этого кода. Это происходит потому, что отправка этого сообщения является частью кода, который в первую очередь создает цепочку сигналов. Вы хотите, чтобы это сообщение отправлялось только при срабатывании catchTo
сигнала.
Я думаю, что вместо -retryWithAlert
немедленной отправки вы хотите отложить это до тех catchTo
пор, пока не будет подписан сигнал ‘d (в этот момент можно отобразить оповещение). Это проще всего сделать с -[RACSignal defer:]
помощью , которая позволяет поместить отправку -retryWithAlert
сообщения в блок, который не вызывается до тех пор, пока не произойдет подписка.
@weakify( self )
[[[[[[_locationManager
rac_fetchLocationSignal]
catchTo:[RACSignal defer:^{ // <--- defer until subscription
@strongify( self );
return [self retryWithAlert];
}]]
flattenMap:^RACStream *( CLLocation *newLocation ) {
@strongify( self )
return [self reverseGeocodeLocation:newLocation];
}]
... (etc)