如何在进行API调用之前使用ReactiveCocoa进行透明身份验证?
我在一个应用程序中使用ReactiveCocoa调用远程Web API。但在从给定API主机检索任何内容之前,应用程序必须提供用户的凭据并检索API令牌,然后用于对后续请求进行签名。
我想抽象掉这个身份验证过程,以便每当我进行API调用时自动发生。假设我有一个包含用户凭据的API客户端类。 // getThing returns RACSignal yielding the data returned by GET /thing. // if the apiClient instance doesn't already have a token,it must // retrieve one before calling GET /thing RAC(self.thing) = [apiClient getThing]; 如何使用ReactiveCocoa透明地导致对API的第一个(且仅第一个)请求检索,并作为副作用,在任何后续请求之前安全地存储API令牌? 这也是一个要求,我可以使用combineLatest :(或类似)启动多个并发请求,他们将隐式等待令牌被检索。 RAC(self.tupleOfThisAndThat) = [RACSignal combineLatest:@[ [apiClient getThis],[apiClient getThat]]]; 此外,如果在进行API调用时检索令牌请求已经处于运行中,那么该API调用必须等待,直到检索令牌请求完成。 我的部分解答如下: 基本模式将是使用flattenMap:将产生令牌的信号映射到一个信号,给定令牌,执行所需的请求并产生API调用的结果。 假设有一些方便的扩展NSURLRequest: - (RACSignal *)requestSignalWithURLRequest:(NSURLRequest *)urlRequest { if ([urlRequest isSignedWithAToken]) return [self performURLRequest:urlRequest]; return [[self getToken] flattenMap:^ RACSignal * (id token) { NSURLRequest *signedRequest = [urlRequest signedRequestWithToken:token]; assert([urlRequest isSignedWithAToken]); return [self requestSignalWithURLRequest:signedRequest]; } } 现在考虑-getToken的订阅实现。 >在琐碎的情况下,当令牌已经被检索时,订阅立即产生令牌。 但我不知道如何做到这一点。此外,如何和在哪里安全地存储令牌?某种持续/可重复信号?
所以,这里有两个主要的事情:
>你想共享一些副作用(在这种情况下,获取令牌),而不是每次有新的订阅者重新触发。 为了共享副作用(上面#1),我们将使用RACMulticastConnection.像文档说:
让我们将其中一个添加为API客户端类的私有属性: @interface APIClient () @property (nonatomic,strong,readonly) RACMulticastConnection *tokenConnection; @end 现在,这将解决所有需要相同的未来结果(API调用在请求令牌正在进行中)的N个当前订阅者的情况,但是我们仍然需要别的以确保未来的订阅者获得相同的结果(已经 – 获取令牌),无论他们什么时候订阅。 这是RACReplaySubject的用途:
为了将这两个概念绑定在一起,我们可以使用RACSignal’s -multicast: method,它通过使用特定类型的主题将正常信号转换为连接。 我们可以在初始化时连接大多数行为: - (id)init { self = [super init]; if (self == nil) return nil; // Defer the invocation of -reallyGetToken until it's actually needed. // The -defer: is only necessary if -reallyGetToken might kick off // a request immediately. RACSignal *deferredToken = [RACSignal defer:^{ return [self reallyGetToken]; }]; // Create a connection which only kicks off -reallyGetToken when // -connect is invoked,shares the result with all subscribers,and // pushes all results to a replay subject (so new subscribers get the // retrieved value too). _tokenConnection = [deferredToken multicast:[RACReplaySubject subject]]; return self; } 然后,我们实现-getToken懒惰地触发抓取: - (RACSignal *)getToken { // Performs the actual fetch if it hasn't started yet. [self.tokenConnection connect]; return self.tokenConnection.signal; } 之后,订阅-getToken(如-requestSignalWithURLRequest :)的结果的任何内容都将获取令牌(如果尚未提取),如果需要,请开始提取令牌,或者等待正在传送的请求(如果有)。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |