潛在的內(nèi)存泄漏及解決方案
1.一定使用@weakify和@strongify
在block里沒(méi)有很直觀的看到self,但是RACObserve的定義里面卻用到了self。
2.使用ReactiveCocoa必須要保證信號(hào)發(fā)送完成或者發(fā)送錯(cuò)誤。
冷熱信號(hào)
RACSubject 及其子類是熱信號(hào)。
RACSignal 排除 RACSubject 類以外的是冷信號(hào)。
冷信號(hào)轉(zhuǎn)化成熱信號(hào)
- (RACMulticastConnection *)publish;
- (RACMulticastConnection *)multicast:(RACSubject *)subject;
- (RACSignal *)replay;
- (RACSignal *)replayLast;
- (RACSignal *)replayLazily;
- (RACMulticastConnection *)multicast:(RACSubject *)subject {
[subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
return connection;
}
/// implementation RACMulticastConnection
- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
NSCParameterAssert(source != nil);
NSCParameterAssert(subject != nil);
self = [super init];
if (self == nil) return nil;
_sourceSignal = source;
_serialDisposable = [[RACSerialDisposable alloc] init];
_signal = subject;
return self;
}
#pragma mark Connecting
- (RACDisposable *)connect {
BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);
if (shouldConnect) {
self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];
}
return self.serialDisposable;
}
- (RACSignal *)autoconnect {
__block volatile int32_t subscriberCount = 0;
return [[RACSignal
createSignal:^(id<RACSubscriber> subscriber) {
OSAtomicIncrement32Barrier(&subscriberCount);
RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
RACDisposable *connectionDisposable = [self connect];
return [RACDisposable disposableWithBlock:^{
[subscriptionDisposable dispose];
if (OSAtomicDecrement32Barrier(&subscriberCount) == 0) {
[connectionDisposable dispose];
}
}];
}]
setNameWithFormat:@"[%@] -autoconnect", self.signal.name];
}
- 當(dāng)RACSignal類的實(shí)例調(diào)用- (RACMulticastConnection *)multicast:(RACSubject *)subject時(shí),以self和subject作為構(gòu)造參數(shù)創(chuàng)建一個(gè)RACMulticastConnection實(shí)例。
- RACMulticastConnection構(gòu)造的時(shí)候,保存source和subject作為成員變量,創(chuàng)建一個(gè)RACSerialDisposable對(duì)象,用于取消訂閱。
- 當(dāng)RACMulticastConnection類的實(shí)例調(diào)用- (RACDisposable *)connect這個(gè)方法的時(shí)候,判斷是否是第一次。如果是的話用_signal這個(gè)成員變量來(lái)訂閱sourceSignal之后返回self.serialDisposable;否則直接返回self.serialDisposable。這里面訂閱sourceSignal是重點(diǎn)。
- RACMulticastConnection的signal只讀屬性,就是一個(gè)熱信號(hào),訂閱這個(gè)熱信號(hào)就避免了各種副作用的問(wèn)題。它會(huì)在- (RACDisposable *)connect第一次調(diào)用后,根據(jù)sourceSignal的訂閱結(jié)果來(lái)傳遞事件。
- 想要確保第一次訂閱就能成功訂閱sourceSignal,可以使用- (RACSignal *)autoconnect這個(gè)方法,它保證了第一個(gè)訂閱者觸發(fā)sourceSignal的訂閱,也保證了當(dāng)返回的信號(hào)所有訂閱者都關(guān)閉連接后sourceSignal被正確關(guān)閉連接。
- (RACMulticastConnection *)publish {
RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
RACMulticastConnection *connection = [self multicast:subject];
return connection;
}
- (RACSignal *)replay {
RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"[%@] -replay", self.name];
RACMulticastConnection *connection = [self multicast:subject];
[connection connect];
return connection.signal;
}
- (RACSignal *)replayLast {
RACReplaySubject *subject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"[%@] -replayLast", self.name];
RACMulticastConnection *connection = [self multicast:subject];
[connection connect];
return connection.signal;
}
- (RACSignal *)replayLazily {
RACMulticastConnection *connection = [self multicast:[RACReplaySubject subject]];
return [[RACSignal
defer:^{
[connection connect];
return connection.signal;
}]
setNameWithFormat:@"[%@] -replayLazily", self.name];
}
-
- (RACMulticastConnection *)publish就是幫忙創(chuàng)建了RACSubject。 -
- (RACSignal *)replay就是用RACReplaySubject來(lái)作為subject,并立即執(zhí)行connect操作,返回connection.signal。其作用是上面提到的replay功能,即后來(lái)的訂閱者可以收到歷史值。 -
- (RACSignal *)replayLast就是用Capacity為1的RACReplaySubject來(lái)替換- (RACSignal *)replay的`subject。其作用是使后來(lái)訂閱者只收到最后的歷史值。 -
- (RACSignal *)replayLazily和- (RACSignal *)replay的區(qū)別就是replayLazily會(huì)在第一次訂閱的時(shí)候才訂閱sourceSignal。
Comparing replay, replayLast, and replayLazily
__block int num = 0;
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}];
NSLog(@"Start subscriptions");
// Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
// Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
// Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Start subscriptions
Increment num to: 1
S1: 1
Increment num to: 2
S2: 2
Increment num to: 3
S3: 3
a normal RACSignal can be thought of as lazy, as it doesn’t do any work until it has a subscriber.

Cold Signal,需要 subscribeNext: 觸發(fā)。且每次都會(huì)執(zhí)行 subscription code。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = letters;
NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"];
NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"];
NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1
Send A
S1: A
Send B
S1: B
Subscribe S2
Send C
S1: C
S2: C
Send D
S1: D
S2: D
Subscribe S3
Our second example shows how each subscriber only receives the values that are sent after their subscription is added.

新增的 subscribe 不同步之前的信號(hào)
__block int num = 0;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}] replay];
NSLog(@"Start subscriptions");
// Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
// Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
// Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Increment num to: 1//這里會(huì)直接執(zhí)行一次 subscription code
Start subscriptions
S1: 1
S2: 1
S3: 1
This example shows how the subscription code is not re-executed upon new subscriptions.
This time the num integer is incremented immediately, before there are even any subscribers. And it is only incremented once, meaning that the subscription code is only been executed a single time, regardless of how many subscribers the signal has.

replay 與 replayLast 會(huì)生成 Hot Signal, 直接執(zhí)行 subscription code ,且只執(zhí)行一次。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replay];
NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"];
NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"];
NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1
Send A
S1: A
Send B
S1: B
Subscribe S2
S2: A
S2: B
Send C
S1: C
S2: C
Send D
S1: D
S2: D
Subscribe S3
S3: A
S3: B
S3: C
S3: D
This example shows how each new subscriber receives the full history of the signal.
Even though S3 subscribed after all of the values had been sent, it still received all of the values.

replay 與 replayLasily 每次添加 subscribe 會(huì)同步所有歷史信號(hào)。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replayLast];
NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"];
NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"];
NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1
Send A
S1: A
Send B
S1: B
Subscribe S2
S2: B
Send C
S1: C
S2: C
Send D
S1: D
S2: D
Subscribe S3
S3: D
This example illustrates how only the most recent value is provided to a new subscriber.

只同步最近一次的歷史信號(hào)
__block int num = 0;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}] replayLazily];
NSLog(@"Start subscriptions");
// Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}];
// Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}];
// Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Start subscriptions
Increment num to: 1//添加 subscribe 后才觸發(fā)執(zhí)行 subscription code
S1: 1
S2: 1
S3: 1
The difference between -replayLazily and -replay is that -replayLazily will not subscribe to the source signal until something subscribes to the newly created signal. This is opposed to the behavior of -replay and -replayLast, which subscribe to the source signal immediately upon being called.

Cold Signal ,需要觸發(fā)才執(zhí)行 subscription code