Skip to content

Commit f91f435

Browse files
committed
RACSubject: avoid retaining the subscribers strongly in the disposable.
The `-subscribe:` method of `RACSubject` is returning a disposable that removes the new subscriber from the collection of active subscribers to that subject. The disposable is disposed when the new subscription is disposed, either explicitly or by having the subject send a completion or error. However, for infinite subjects that are not manually disposed, the subscriber will be kept in memory forever. This happens because the subscriber holds the disposable, which in turns holds the subscriber. To break the cycle, the subscriber and the collection of subscribers needs to be held weakly. Based on joomcode@9b27795.
1 parent afc23f6 commit f91f435

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

ReactiveObjC/RACSubject.m

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,14 @@ - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
6161
@synchronized (subscribers) {
6262
[subscribers addObject:subscriber];
6363
}
64-
64+
65+
@rac_weakify(subscribers, subscriber);
6566
[disposable addDisposable:[RACDisposable disposableWithBlock:^{
67+
@rac_strongify(subscribers, subscriber);
68+
if (!subscribers || !subscriber) {
69+
return;
70+
}
71+
6672
@synchronized (subscribers) {
6773
// Since newer subscribers are generally shorter-lived, search
6874
// starting from the end of the list.

ReactiveObjCTests/RACSubjectSpec.m

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,28 @@ - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
7272
});
7373

7474
qck_it(@"should dispose the paired disposable when a subscription terminates", ^{
75-
RACSubject* subject = [RACSubject new];
76-
RACTestSubscriber* subscriber = [RACTestSubscriber new];
75+
RACSubject *subject = [RACSubject new];
76+
RACTestSubscriber *subscriber = [RACTestSubscriber new];
7777

7878
[[subject subscribe:subscriber] dispose];
7979

8080
expect(@(subscriber.disposable.disposed)).to(beTruthy());
8181
});
8282

83+
qck_it(@"should release the subscriber after subject deallocation", ^{
84+
__weak RACTestSubscriber *weakSubscriber;
85+
86+
@autoreleasepool {
87+
RACTestSubscriber *subscriber = [RACTestSubscriber new];
88+
weakSubscriber = subscriber;
89+
RACSubject *subject = [RACSubject subject];
90+
91+
[subject subscribe:subscriber];
92+
}
93+
94+
expect(weakSubscriber).to(beNil());
95+
});
96+
8397
qck_itBehavesLike(RACSubscriberExamples, ^{
8498
return @{
8599
RACSubscriberExampleSubscriber: subject,

0 commit comments

Comments
 (0)