Запрашивать повторную попытку при сбое вызова сетевого API с помощью ReactiveCocoa.

Я использую ReactiveCocoa в своем приложении iOS для запросов сетевого API. Что, если я хочу показать UIAlertView и попросить пользователя нажать кнопку повтора, а повторная попытка того же вызова API произойдет только тогда, когда пользователь нажмет кнопку повтора, как это должно быть?

- (RACSignal*) fetchImportantData {
    return [RACSignal createSignal: ^RACDisposable*(id<RACSubscriber> subscriber) {
        return [apiCall subscribeNext:^(id x) {
            [subscriber sendNext:x]; 
            [subscriber sendCompleted];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        }];
    }];
}

person syshen    schedule 27.05.2015    source источник


Ответы (1)


Это должно сработать.

RACSignal * catchSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    UIAlertView * alertView = [[UIAlertView alloc]
                               initWithTitle:@"Try again"
                               message:@""
                               delegate:nil
                               cancelButtonTitle:@"No"
                               otherButtonTitles:@"Yes", nil];
    [alertView.rac_buttonClickedSignal subscribeNext:^(NSNumber * buttonIndex) {
        if (buttonIndex.integerValue != alertView.cancelButtonIndex)
        {
            [subscriber sendCompleted];
        }
        else
        {
            [subscriber sendError:nil];
        }
    }];
    [alertView show];
    return nil;
}];

[[[[[self fetchImportantData] catchTo:catchSignal] repeat] take:1] subscribeNext:^(id x) {
    NSLog(@"NEXT: %@", x);
} error:^(NSError *error) {
    NSLog(@"ERROR: %@", error);
} completed:^{
    NSLog(@"COMPLETED");
}];

Итак, здесь происходит то, что ошибка от fetchImportantData перехватывается catchTo:, а затем сигнал заменяется тем, что отправляется этим сигналом (это похоже на flattenMap:, но для ошибок). Поскольку теперь у нас есть контроль, мы можем подключить sendCompleted к кнопке «Да» и использовать repeat для повторения сигнала после завершения, а sendError: подключить к кнопке «Нет», чтобы мы могли немедленно прекратить подписку, если пользователь не хочет повторять.

Когда fetchImportantData, наконец, вернет не ошибку, он будет отправлен и полностью пропустит наш блок catchTo:, а сигнал завершится благодаря нашему take:1.

person Charles Maria    schedule 27.05.2015