RAC(ReactiveCocoa)介绍(五)——RACPass
上一篇整体分析了RAC的信号流程,这样对RAC的工作原理有了整体的认识。
接下来将逐步深入了解RAC实现的底层。
RACPassthroughSubscriber类
在上一篇文章的流程分析中,真正的订阅者是RACPassthroughSubscriber类,它将创建信号、订阅者与销毁者进行了关联。
在RACPassthroughSubscriber类的头文件中,声明了一个RACSignal类的成员变量。
@property (nonatomic, unsafe_unretained, readonly) RACSignal *signal;
在声明的属性中,定义了signal为unsafe_unretained,意味着signal为弱引用,但又与weak属性不同。weak属性当为nil时,对象会自动执行释放功能,导致该对象无法继续被使用。而unsafe_unretained同样作为弱引用,当为nil时却指针不会自动释放,保留一个野指针。如果使用此指针,程序会抛出 BAD_ACCESS 的异常。
在此处多问一个为什么,此处信号为什么要使用unsafe_unretained而不是weak属性修饰?
找了网上的几处分析,都在说下面这句:
这里之所以不是weak,是因为引用RACSignal仅仅只是一个DTrace probes动态跟踪技术的探针。如果设置成weak,会造成没必要的性能损失。
个人理解:unsafe_unretained属性不会自动将signal变为nil,而weak属性会自动置为nil。当signal置为nil时,当前signal不再是一个信号类型的对象,就无法再继续执行订阅信号、发送信号动作。所以要使用unsafe_unretained属性保留当前signal的类型,即使变成了野指针。

首先,此处的成员变量signal声明为RACSignal类,是RACPassthroughSubscriber类实例化方法执行时传入的。而该信号又是从RACDynamicSignal传来的,RACDynamicSignal持有了当前的subscribe;subscribe继续向上溯源,找到了在RACSignal类中的[self subscribe:o]方法。那么答案已经显而易见了,unsafe_unretained属性的声明,就是为了防止在此过程中的循环引用。

在RACSignal类的订阅方法subscribeNext方法中,当执行订阅信号时,self通过LLDB打印出的却是RACDynamicSignal类。

首先RACDynamicSignal类是RACSignal类的子类,此处进行了RACSignal类的分类扩展在分类中实现了subscribeNext方法。在创建信号时,信号类为RACDynamicSignal类。

在发送信号时,打印subscriber会发现其所属类为RACPassthroughSubscriber。

self.innerSubscriber对象为RACSubscriber类创建的,最终是执行RACSubscriber类下的sendNext方法,执行nextBlock。在执行时,@synchronized (self)用于保证线程安全

以上就是针对RACPassthroughSubscriber类的实现进行了一个简单的分析,后续会不断补充、修改。