当我创建一个信号并将其带入函数的范围时,其每个Cocoa约定的有效保留计数为0:
RACSignal *signal = [self createSignal];
Run Code Online (Sandbox Code Playgroud)
当我订阅信号时,它会保留订阅者并返回一个一次性的,根据Cocoa约定,它也有一个保留计数为零.
RACDisposable *disposable = [signal subscribeCompleted:^ {
doSomethingPossiblyInvolving(self);
}];
Run Code Online (Sandbox Code Playgroud)
大多数情况下,订户将关闭并引用self
其ivars或封闭范围的其他部分.因此,当您订阅信号时,信号具有对订户的拥有参考,并且订户具有您自己的参考.你得到的一次性用品有一个信号的拥有参考.
disposable -> signal -> subscriber -> calling scope
Run Code Online (Sandbox Code Playgroud)
假设您持有该一次性用品,以便您可以在某个时间点取消订阅(例如,如果信号是从Web服务检索数据并且用户导航离开屏幕,则取消她查看正在检索的数据的意图).
self.disposeToCancelWebRequest = disposable;
Run Code Online (Sandbox Code Playgroud)
此时我们有一个循环参考:
calling scope -> disposable -> signal -> subscriber -> calling scope
Run Code Online (Sandbox Code Playgroud)
负责任的事情是确保在取消请求或请求完成后循环中断.
[self.disposeToCancelWebRequest dispose]
self.disposeToCancelWebRequest = nil;
Run Code Online (Sandbox Code Playgroud)
请注意,self
在释放时不能执行此操作,因为保留周期永远不会发生这种情况!在回调用户期间,在打破保留周期方面看起来似乎有些可疑,因为信号可能在其实现仍然在调用堆栈上时被释放.
我还注意到实现保留了一个进程全局活动信号列表(截至我最初提出这个问题时).
使用RAC时如何考虑所有权?
我在一个应用程序中使用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];
Run Code Online (Sandbox Code Playgroud)
如何使用ReactiveCocoa透明地导致API的第一个(也是唯一的)请求检索,并且作为副作用,在发出任何后续请求之前安全地存储API令牌?
我还可以使用combineLatest:
(或类似的)启动多个同时发出的请求,并且它们都会隐式等待检索令牌.
RAC(self.tupleOfThisAndThat) = [RACSignal combineLatest:@[ [apiClient getThis], [apiClient getThat]]];
Run Code Online (Sandbox Code Playgroud)
此外,如果在进行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 = …
Run Code Online (Sandbox Code Playgroud) 使用ReactiveCocoa,似乎有两种方法让订阅者从信号中接收相同的值,而不是重新触发生成这些值的任何操作:通过RACReplaySubject或RACMulticastConnection.
以下是RACReplaySubject的标题文档:
重播主题保存发送的值(达到其定义的容量)并将其重新发送给新订户.它还将重播错误或完成.
对于RACMulticastConnection:
多播连接封装了向许多订户共享信号订阅的想法.如果对基础信号的订阅涉及副作用或不应多次调用,则通常需要这样做.
多播信号仅在
-[RACMulticastConnection connect]
被呼叫时订阅 .在此之前,不会发送任何值signal
.了解-[RACMulticastConnection autoconnect]
如何-[RACMulticastConnection connect]
自动调用.请注意,您不应手动创建RACMulticastConnection.而是使用
-[RACSignal publish]
或-[RACSignal multicast:]
.
有人可以提供关于何时使用RACReplaySubject或RACMulticastConnection的简单指南?
如果RACSignal
没有订阅者,我将如何实现停止发布?如果有订阅者则自动启动?
这是一个场景:
让我们说我有一个currentLocationSignal
在AppDelegate
.当视图卸载时,我LocationViewController
会订阅currentLocationSignal
视图加载和取消订阅(dispose).由于获取当前位置需要几秒钟,我希望始终订阅currentLocationSignal
应用程序打开的时间(并在几秒钟后自动取消订阅),所以当我到达时,LocationViewController
我会得到一个准确的位置.因此,信号可能有多个订户.当第一个用户收听时,它需要开始呼叫startUpdatingLocation
,当没有用户需要呼叫时stopUpdatingLocation
.
cocoa-touch objective-c reactive-programming ios reactive-cocoa