Retrying an asynchronous operation using ReactiveCocoa

放肆的年华 提交于 2019-11-30 09:52:20

First of all, subscriptions and subjects should generally be avoided as much as possible. Nested subscriptions, in particular, are quite an anti-pattern—usually there are signal operators that can replace them.

In this case, we need to take advantage of the fact that signals can represent deferred work, and create only one signal to perform the actual request:

// This was originally the `first` signal.
RACSignal *apiCall = [RACSignal defer:^{
    return [self apiCall:base params:p get:get];
}];

The use of +defer: here ensures that no work will begin until subscription. An important corollary is that the work can be repeated by subscribing multiple times.

For example, if we catch an error, we can try fetching a token, then return the same deferred signal to indicate that it should be attempted again:

return [[apiCall
    catch:^(NSError *error) {
        // If an error occurs, try requesting a token.
        return [[self
            action:@"logon" email:session.user.email password:session.user.password]
            flattenMap:^(NSDictionary *json) {
                NSString *token = json[@"token"];

                p[@"token"] = token;
                session.token = token;

                // Now that we have a token, try the original API call again.
                return apiCall;
            }];
    }]
    replay];

The use of -replay replaces the RACReplaySubject that was there before, and makes the request start immediately; however, it could also be -replayLazily or even eliminated completely (to redo the call once per subscription).

That's it! It's important to point out that no explicit subscription was needed just to set up the work that will be performed. Subscription should generally only occur at the "leaves" of the program—where the caller actually requests that work be performed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!