Каков наилучший способ сбросить сигнал таймера?

Мне нужно получать данные с сервера каждые 5 минут. Если я выполняю обновление по запросу, мне также нужно получить данные с сервера и сбросить таймер.

Ниже приведен код решения, выглядит отлично. Просто интересно, как упростить код? Возможно, в ReactiveCocoa есть способ получше?

    RACSignal* refreshSignal = [self.refreshControl rac_signalForControlEvents:UIControlEventValueChanged];
    self.timerSignal = [[RACSignal interval:300 onScheduler:[RACScheduler scheduler] withLeeway:2] takeUntil:refreshSignal];
    [self.timerSignal subscribeNext:^(id x) {
        NSLog(@"==========================");
        NSLog(@"[Timer1]");
        [self.viewModel performFetch];
    }];

    [refreshSignal subscribeNext:^(id x) {
        NSLog(@"==========================");
        NSLog(@"[Refresh]");
        [self.viewModel performFetch];
        self.timerSignal = [[RACSignal interval:300 onScheduler:[RACScheduler scheduler] withLeeway:2] takeUntil:refreshSignal];
        [self.timerSignal subscribeNext:^(id x) {
            NSLog(@"==========================");
            NSLog(@"[Timer2]");
            [self.viewModel performFetch];
        }];
    }];

person JerryZhou    schedule 21.08.2015    source источник


Ответы (2)


Самым чистым способом, который я могу придумать, было бы использование RACReplaySubject, отправка interval сигналов 300, а затем переключение на последний сигнал, отправленный каждый раз, когда блок запускается.

self.timerSubject = [RACReplaySubject replaySubjectWithCapacity:1];
RACSignal * refreshSignal = [self.refreshControl rac_signalForControlEvents:UIControlEventValueChanged];
RACSignal * timeSignal = [RACSignal interval:300 onScheduler:[RACScheduler scheduler] withLeeway:2];
[self.timerSubject sendNext:timeSignal];

@weakify(self)
[[self.timerSubject.switchToLatest merge:refreshSignal] subscribeNext:^(id _) {
    @strongify(self)
    [self.viewModel performFetch];
}];

[refreshSignal subscribeNext:^(id _) {
    @strongify(self)
    [self.timerSubject sendNext:timeSignal];
}];
person Charles Maria    schedule 21.08.2015
comment
Да, ваш код намного чище моего. Просто не знаком с RACReplaySubject. - person JerryZhou; 21.08.2015
comment
RACReplaySubject — это своего рода ручной сигнал. Это похоже на изменяемую переменную, эквивалентную функциональному реактивному миру. Вы вручную указываете, когда отправлять next, error и completed. Поскольку его емкость составляет 1, он сохраняет последние отправленные next и пересылает их всем новым подпискам. - person Charles Maria; 21.08.2015
comment
Я проверил ваш код, только одна небольшая проблема (или, может быть, это особенность): задержка может задерживать 300 или 301 секунду, и ему не нравится таймер с withLeeway, чтобы сместить интервал назад; Что дает таймер, так это то, что если он составляет 301 секунду, в следующий раз он может вернуться к 209 секундам, чтобы сделать его соболиным. - person JerryZhou; 21.08.2015
comment
Но ваш код - хорошее предложение для меня. Я просто думаю, что 300 в среднем было бы лучше. Просто потому, что накопительный эффект смещения стал бы огромным. - person JerryZhou; 21.08.2015
comment
Отредактировано для использования таймера. - person Charles Maria; 21.08.2015
comment
У меня есть редактирование, чтобы включить сигнал запуска. sendNext:[RACSignal return:nil] - person JerryZhou; 21.08.2015
comment
И я никогда не думал о sendNext: с сигналом раньше ваш ответ расширил мой кругозор. - person JerryZhou; 21.08.2015
comment
Рад помочь, я надеюсь, что это достаточно хорошо, чтобы быть принятым ответом. - person Charles Maria; 21.08.2015

Я бы сопоставил сигнал обновления с сигналом таймера. Каждый раз, когда RefreshSignal отправляет значение, оно сопоставляется с сигналом, отправляющим значение каждые пять минут.

В качестве примечания я думаю, что эта логика принадлежит модели представления. Там результирующий сигнал может быть сопоставлен с сетевым запросом с помощью flatMap:. Затем текущий сетевой запрос будет отменен, если пользователь снова быстро обновится.

[[[[refreshSignal startWith:nil]
map:^id(id value) {
    return [[RACSignal interval:5 * 60 onScheduler:[RACScheduler mainThreadScheduler]] startWith:nil];
}]
switchToLatest]
subscribeNext:^(id x) {
    @strongify(self)
    [self.viewModel performFetch];
}];
person andersfrank    schedule 30.08.2015
comment
Спасибо за повтор, позже проверю. - person JerryZhou; 01.09.2015