#objective-c #reactive-cocoa
#objective-c #реактивный-cocoa
Вопрос:
Я только начал изучать Reactive Cocoa и подумал, что сценарий из многих приложений, с которыми я сейчас работаю, должен быть хорошей отправной точкой. При запуске приложения оно проверяет, находится ли пользователь в настоящее время в стране, занесенной в белый список, прежде чем разрешить пользователю войти в приложение. Итак, идеальная последовательность должна выглядеть примерно так:
- Проверьте местоположение устройства, используя местоположение ядра.
- Обратный код местоположения с помощью CLGeocoder.
- Сравните код страны с белым списком.
- Продолжайте загрузку приложения.
Если (1) не удается, я хочу сообщить пользователю, что службы определения местоположения должны быть включены с помощью a UIAlertView
с помощью одной кнопки повтора. И именно здесь я, похоже, не могу понять, как это должно быть сделано. Текущий код ниже:
@weakify( self )
[[[[[[self
findLocation]
doError:^( NSError *error ) {
@strongify( self )
// There was an error fetching the location so we ask
// the user to enable location services.
//
[self askUserToEnableLocationServices];
}]
retry] // What do we really retry here? It doesn't seem like it's [self findLocation]
flattenMap:^RACStream *( CLLocation *newLocation ) {
@strongify( self )
return [self reverseGeocodeLocation:newLocation];
}]
flattenMap:^RACStream *( NSString *ISOCountryCode ) {
@strongify( self )
return [self checkCountryPermissibleSignal:ISOCountryCode];
}]
subscribeNext:^( id x ) {
NSLog( @"Country is valid!" );
} error:^( NSError *error ) {
NSLog( @"Error: %@", error );
}];
У кого-нибудь есть какие-либо данные по этому поводу? Я предполагаю, что я ошибаюсь в том, как retry
это работает. Я также подозреваю, что я немного наивен в отношении того, как должен выглядеть весь поток. Но я застрял на этом уже пару вечеров. Есть что-то, что еще не щелкнуло.
Ответ №1:
Просто заметил, что вы спросили об этом на SO. Я опубликовал ответ в репозитории GitHub, но для потомков я также опубликую свой ответ здесь:
@weakify( self )
[[[[[[self
findLocation]
doError:^( NSError *error ) {
@strongify( self )
// There was an error fetching the location so we ask
// the user to enable location services.
//
[self askUserToEnableLocationServices];
}]
retry] // What do we really retry here? It doesn't seem like it's [self findLocation]
-retry
больше не вызывается [self findLocation]
. Вместо этого он создает новую подписку на объект RACSignal, который был возвращен [self findLocation]
. Исходная подписка удалена из-за доставки ошибки в соответствии с контрактом / семантикой того, как работают сигналы при отправке ошибки.
Обратите внимание, что код в вашем вызове -doError:
будет выполняться одновременно с новой подпиской, что может быть не тем, что вы предполагали. Другими словами, пока вы показываете пользователю представление предупреждения, вы одновременно повторно подписываетесь на сигнал -findLocation
, возвращенный до того, как у пользователя была возможность предпринять какие-либо действия.
Вы можете использовать -catchTo:
, чтобы указать альтернативный сигнал, на который следует подписаться, если в исходном сигнале выдается ошибка:
@weakify( self )
RACSignal *recover = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
@strongify( self );
[self askTheUserToEnableLocationServices]
return nil;
}];
[[[[[self
findLocation]
catchTo:recover]
flattenMap:^RACStream *( CLLocation *newLocation ) {
@strongify( self )
return [self reverseGeocodeLocation:newLocation];
}]
flattenMap:^RACStream *( NSString *ISOCountryCode ) {
@strongify( self )
return [self checkCountryPermissibleSignal:ISOCountryCode];
}]
subscribeNext:^( id x ) {
NSLog( @"Country is valid!" );
} error:^( NSError *error ) {
NSLog( @"Error: %@", error );
}];
Комментарии:
1. Во-первых: да, я тоже задавал вопрос на GitHub. Больше крючков, больше рыбы? С этого момента я буду придерживаться SO, поскольку, похоже, вы отслеживаете оба. Во-вторых: я понимаю, что я действительно задал неправильный вопрос. То, что я намеревался спросить, было больше о том, как мне следует повторить первый шаг последовательности, пока пользователь не изменит настройки, чтобы разрешить службы определения местоположения для приложения. Но ваш ответ действительно привел меня в правильном направлении и ответил на вопрос, поэтому я принимаю его. Теперь я застрял на другой проблеме с этим кодом. Я свяжу его, когда вопрос будет поднят на SO.