仅对新订户进行信号重试

时间:2014-03-04 00:45:46

标签: ios reactive-cocoa

我正在使用缓存重播信号的典型模式:

- (RACSignal *)resultSignal {
    if (!_resultSignal) {
        _resultSignal = [self createResultSignal];
    }

    return _resultSignal;
}

- (RACSignal *)createResultSignal {
    return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [someObject doWorkWithCompletionBlock:^(id result) {
            [subscriber sendNext:result];
            [subscriber sendCompleted];
        }
                                failure:^(NSError *error) {
            [subscriber sendError:error];
        }];

        return nil;
    }] replay];
}

这很好用,但现在我想添加重试功能,如果工作失败了。我可以使用-[RACSignal retry]-[RACSignal retry:],但这不会立即通知订阅者错误。相反,我想要的是这个信号的现有用户得到错误,但随后调用-resultSignal来接收新信号,或重试现有信号。

我可以-catch:此信号并将_resultSignal设置为nil,然后我不得不担心竞争条件,我不认为是“反应性”的方式来做到这一点。

实现此行为的适当方法是什么?

更新

感谢@joshaber!我最终采用了我建议的方法,我认为这不是太糟糕:

- (RACSignal *)resultSignal {
    @synchronized(_resultSignal) {
        if (!_resultSignal) {
            @weakify(self);

            _resultSignal = [[self createResultSignal] catch:^RACSignal *(NSError *error) {
                @strongify(self);

                self.resultSignal = nil;
                return [RACSignal error:error];
            }];
        }

        return _resultSignal;
    }
}

- (void)setResultSignal:(RACSignal *)signal {
    @synchronized(_resultSignal) {
        _resultSignal = signal;
    }
}

1 个答案:

答案 0 :(得分:1)

我一直在思考这个问题。如果我希望我有一个很好的答案会有帮助吗? ;)

  

我可以-catch:这个信号并在块中将_resultSignal设置为nil,但是我不得不担心竞争条件,我不认为这是“反应性”的方式来做到这一点。

这是我倾向于的。

或者,您可以使用信号信号。它会发送最新信号。现有订户将订阅旧信号,新订户将获得重试信号。但这可能需要手动使用RACSubject,所以我不知道与其他解决方案相比,额外的复杂性是值得的。