Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Replace connectable signals with multicast connections #235

Merged
merged 12 commits into from

2 participants

@joshaber
Owner

This replaces RACConnectableSignal with RACMulticastConnection, as discussed in #214.

I also removed RACCancelableSignal since it was a subclass of RACConnectableSignal and it seemed silly to spend time updating something that was going away. (#73)

There are a couple open questions still:

  1. In #214 we talked about dropping -autoconnect, but it seems like we still need something like that which disposes of the shared subscription automatically. I made changes to -autoconnect to make it safe compared to what it was.

  2. Should -replayLazily use -autoconnect? I'm leaning towards yes.

@joshaber joshaber referenced this pull request
Closed

Added -memoize #214

@joshaber
Owner

I went ahead and changed -replayLazily to use -autoconnect.

@jspahrsummers jspahrsummers was assigned
RACExtensions/NSTask+RACSupport.m
((11 lines not shown))
NSParameterAssert(scheduler != nil);
+ __weak NSTask *weakSelf = self;
@jspahrsummers Owner

This should be able to use EXTScope, since it's included in RAC proper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
RACExtensions/NSTask+RACSupport.m
((11 lines not shown))
NSParameterAssert(scheduler != nil);
+ __weak NSTask *weakSelf = self;
+ return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
@jspahrsummers Owner

Shouldn't this be multicasted?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.h
((17 lines not shown))
+// Note that you shouldn't create RACMulticastConnection manually. Instead use
+// -[RACSignal publish] or -[RACSignal multicast:].
+@interface RACMulticastConnection : NSObject
+
+// The multicasted signal.
+@property (nonatomic, strong, readonly) RACSignal *signal;
+
+// Connect to the underlying signal by subscribing to it. Calling this multiple
+// times does nothing but return the existing connection's disposable.
+//
+// Returns the disposable for the subscription to the multicasted signal.
+- (RACDisposable *)connect;
+
+// Connects to the underlying signal when the returned signal is first
+// subscribed to and disposes of the subscription to the multicasted signal when
+// the returned signal has no subscribers.
@jspahrsummers Owner

We should make it very clear that this doesn't reconnect at any point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.h
((16 lines not shown))
+//
+// Note that you shouldn't create RACMulticastConnection manually. Instead use
+// -[RACSignal publish] or -[RACSignal multicast:].
+@interface RACMulticastConnection : NSObject
+
+// The multicasted signal.
+@property (nonatomic, strong, readonly) RACSignal *signal;
+
+// Connect to the underlying signal by subscribing to it. Calling this multiple
+// times does nothing but return the existing connection's disposable.
+//
+// Returns the disposable for the subscription to the multicasted signal.
+- (RACDisposable *)connect;
+
+// Connects to the underlying signal when the returned signal is first
+// subscribed to and disposes of the subscription to the multicasted signal when
@jspahrsummers Owner

*to, and (just for readability)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jspahrsummers jspahrsummers commented on the diff
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.m
((4 lines not shown))
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+#import "RACMulticastConnection.h"
+#import "RACMulticastConnection+Private.h"
+#import "RACSubject.h"
+#import "RACCompoundDisposable.h"
+#import "RACSignal+Private.h"
+
+@interface RACMulticastConnection () {
+ RACSubject *_signal;
+}
+
+@property (nonatomic, readonly, strong) RACSignal *sourceSignal;
@jspahrsummers Owner

Can you please document what needs synchronization here?

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...mework/ReactiveCocoa/RACMulticastConnection+Private.h
@@ -0,0 +1,17 @@
+//
+// RACMulticastConnection+Private.h
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+#import "RACMulticastConnection.h"
+
+@class RACSubject;
+
+@interface RACMulticastConnection ()
+
++ (instancetype)connectionWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject;
@jspahrsummers Owner

Why not use an -init… method for this, if it's private anyways? It would make the ivar access nicer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.m
((13 lines not shown))
+#import "RACSignal+Private.h"
+
+@interface RACMulticastConnection () {
+ RACSubject *_signal;
+}
+
+@property (nonatomic, readonly, strong) RACSignal *sourceSignal;
+@property (nonatomic, readonly, strong) RACCompoundDisposable *disposable;
+@property (nonatomic, assign) BOOL hasConnected;
+@end
+
+@implementation RACMulticastConnection
+
+#pragma mark Lifecycle
+
++ (instancetype)connectionWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
@jspahrsummers Owner

Should this assert that both arguments are non-nil?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.m
((36 lines not shown))
+ self = [super init];
+ if (self == nil) return nil;
+
+ _disposable = [RACCompoundDisposable compoundDisposable];
+
+ return self;
+}
+
+#pragma mark Connecting
+
+- (RACDisposable *)connect {
+ @synchronized(self) {
+ if (!self.hasConnected) {
+ self.hasConnected = YES;
+
+ RACDisposable *sourceDisposable = [self.sourceSignal subscribe:_signal];
@jspahrsummers Owner

This doesn't need to be synchronized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jspahrsummers jspahrsummers commented on the diff
...CocoaFramework/ReactiveCocoa/RACMulticastConnection.h
((1 lines not shown))
+//
+// RACMulticastConnection.h
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+@class RACSignal;
+@class RACDisposable;
+
+// A multicast connection encapsulates the idea of sharing one subscription to a
+// signal to many subscribers. This is most often needed if the subscription to
+// the underlying signal involves side-effects or shouldn't be called more than
+// once.
+//
@jspahrsummers Owner

We should add another paragraph here, talking about how to activate the receiver's signal (and what it means to do so).

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
((12 lines not shown))
// subject. This allows you to share a single subscription to the underlying
// signal.
-- (RACConnectableSignal *)multicast:(RACSubject *)subject;
+- (RACMulticastConnection *)multicast:(RACSubject *)subject;
+
+// Multicasts the signal to a RACReplaySubject and connects.
@jspahrsummers Owner

"connects immediately" might make it clearer that this has side effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
((12 lines not shown))
// subject. This allows you to share a single subscription to the underlying
// signal.
-- (RACConnectableSignal *)multicast:(RACSubject *)subject;
+- (RACMulticastConnection *)multicast:(RACSubject *)subject;
+
+// Multicasts the signal to a RACReplaySubject and connects.
+//
+// Returns the connection's signal.
+- (RACSignal *)replay;
+
+// Multicasts the signal to a RACReplaySubject. It will connect the multicast
+// connection on the first subscription.
@jspahrsummers Owner

This should clarify that it uses -autoconnect and inherits all the semantics of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
((12 lines not shown))
// subject. This allows you to share a single subscription to the underlying
// signal.
-- (RACConnectableSignal *)multicast:(RACSubject *)subject;
+- (RACMulticastConnection *)multicast:(RACSubject *)subject;
+
+// Multicasts the signal to a RACReplaySubject and connects.
+//
+// Returns the connection's signal.
@jspahrsummers Owner

This is the first reference to "the connection," and it might be unclear what it means.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
((12 lines not shown))
// subject. This allows you to share a single subscription to the underlying
// signal.
-- (RACConnectableSignal *)multicast:(RACSubject *)subject;
+- (RACMulticastConnection *)multicast:(RACSubject *)subject;
+
+// Multicasts the signal to a RACReplaySubject and connects.
+//
+// Returns the connection's signal.
+- (RACSignal *)replay;
+
+// Multicasts the signal to a RACReplaySubject. It will connect the multicast
@jspahrsummers Owner

*the RACMulticastConnection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.m
@@ -912,15 +912,29 @@ - (RACSequence *)sequence {
return sequence;
}
-- (RACConnectableSignal *)publish {
- RACConnectableSignal *signal = [self multicast:[RACSubject subject]];
- signal.name = [NSString stringWithFormat:@"[%@] -publish", self.name];
- return signal;
+- (RACMulticastConnection *)publish {
+ RACSubject *subject = [RACSubject subject];
+ RACMulticastConnection *connection = [self multicast:subject];
+ subject.name = [NSString stringWithFormat:@"[%@] -publish", self.name];
+ return connection;
+}
+
+- (RACMulticastConnection *)multicast:(RACSubject *)subject {
+ RACMulticastConnection *connection = [RACMulticastConnection connectionWithSourceSignal:self subject:subject];
+ connection.signal.name = [NSString stringWithFormat:@"[%@] -multicast: %@", self.name, subject];
@jspahrsummers Owner

This is equivalent to subject.name = …, and so will change the name of the subject given by the user. Maybe that's okay, but it could be confusing.

@joshaber Owner
joshaber added a note

Yeah though it'll include the original name as part of including subject in the name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...veCocoaFramework/ReactiveCocoa/RACSignal+Operations.m
((19 lines not shown))
}
-- (RACConnectableSignal *)multicast:(RACSubject *)subject {
- RACConnectableSignal *signal = [RACConnectableSignal connectableSignalWithSourceSignal:self subject:subject];
- signal.name = [NSString stringWithFormat:@"[%@] -multicast: %@", self.name, subject];
+- (RACSignal *)replay {
+ RACMulticastConnection *connection = [self multicast:[RACReplaySubject subject]];
+ [connection connect];
+ connection.signal.name = [NSString stringWithFormat:@"[%@] -replay", self.name];
@jspahrsummers Owner

Why not name the RACReplaySubject passed in, mirroring the pattern of -publish?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jspahrsummers jspahrsummers commented on the diff
...ework/ReactiveCocoaTests/RACMulticastConnectionSpec.m
((26 lines not shown))
+ disposed = YES;
+ }];
+ }] publish];
+ expect(subscriptionCount).to.equal(0);
+});
+
+describe(@"-connect", ^{
+ it(@"should subscribe to the underlying signal", ^{
+ [connection connect];
+ expect(subscriptionCount).to.equal(1);
+ });
+
+ it(@"should return the same disposable for each invocation", ^{
+ RACDisposable *d1 = [connection connect];
+ RACDisposable *d2 = [connection connect];
+ expect(d1).to.equal(d2);
@jspahrsummers Owner

This test should also verify that subscriptionCount is still one.

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jspahrsummers jspahrsummers commented on the diff
...ework/ReactiveCocoaTests/RACMulticastConnectionSpec.m
((17 lines not shown))
+__block RACMulticastConnection *connection;
+__block BOOL disposed = NO;
+
+beforeEach(^{
+ subscriptionCount = 0;
+ disposed = NO;
+ connection = [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
+ subscriptionCount++;
+ return [RACDisposable disposableWithBlock:^{
+ disposed = YES;
+ }];
+ }] publish];
+ expect(subscriptionCount).to.equal(0);
+});
+
+describe(@"-connect", ^{
@jspahrsummers Owner

Can you also add a test that verifies the behavior of -connect (same disposable returned, no new subscription) after the original subscription is terminated?

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jspahrsummers jspahrsummers commented on the diff
...ework/ReactiveCocoaTests/RACMulticastConnectionSpec.m
((47 lines not shown))
+
+ beforeEach(^{
+ autoconnectedSignal = [connection autoconnect];
+ });
+
+ it(@"should subscribe to the multicasted signal on the first subscription", ^{
+ expect(subscriptionCount).to.equal(0);
+
+ [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+
+ [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+ });
+
+ it(@"should dispose of the multicasted subscription when the signal has no subscribers", ^{
@jspahrsummers Owner

It might be a bit redundant with this test, but I still think it'd be a good idea to verify that a new subscription doesn't automatically reconnect.

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@joshaber
Owner

:cherry_blossom:

@jspahrsummers jspahrsummers merged commit fccc25f into master

1 check passed

Details default Build #220421 succeeded in 16s
@jspahrsummers jspahrsummers deleted the multicast branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 359 additions and 412 deletions.
  1. +2 −2 RACExtensions/NSTask+RACSupport.h
  2. +50 −38 RACExtensions/NSTask+RACSupport.m
  3. +18 −37 ReactiveCocoaFramework/ReactiveCocoa.xcodeproj/project.pbxproj
  4. +4 −4 ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACLifting.m
  5. +0 −17 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal+Private.h
  6. +0 −22 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal.h
  7. +0 −50 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal.m
  8. +1 −1  ReactiveCocoaFramework/ReactiveCocoa/RACCompoundDisposable.h
  9. +0 −17 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal+Private.h
  10. +0 −29 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal.h
  11. +0 −73 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal.m
  12. +17 −0 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection+Private.h
  13. +46 −0 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.h
  14. +81 −0 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.m
  15. +18 −16 ReactiveCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
  16. +28 −25 ReactiveCocoaFramework/ReactiveCocoa/RACSignal+Operations.m
  17. +0 −1  ReactiveCocoaFramework/ReactiveCocoa/RACSignalSequence.m
  18. +1 −2  ReactiveCocoaFramework/ReactiveCocoa/ReactiveCocoa.h
  19. +0 −78 ReactiveCocoaFramework/ReactiveCocoaTests/RACConnectableSignalSpec.m
  20. +93 −0 ReactiveCocoaFramework/ReactiveCocoaTests/RACMulticastConnectionSpec.m
View
4 RACExtensions/NSTask+RACSupport.h
@@ -52,9 +52,9 @@ extern const NSInteger NSTaskRACSupportNonZeroTerminationStatus;
// NSTaskRACSupportOutputData, NSTaskRACSupportErrorData, and NSTaskRACSupportTask.
//
// scheduler - cannot be nil.
-- (RACCancelableSignal *)rac_runWithScheduler:(RACScheduler *)scheduler;
+- (RACSignal *)rac_runWithScheduler:(RACScheduler *)scheduler;
// Calls -rac_runWithScheduler: with the immediate scheduler.
-- (RACCancelableSignal *)rac_run;
+- (RACSignal *)rac_run;
@end
View
88 RACExtensions/NSTask+RACSupport.m
@@ -9,6 +9,7 @@
#import "NSTask+RACSupport.h"
#import "NSFileHandle+RACSupport.h"
#import "NSNotificationCenter+RACSupport.h"
+#import "EXTScope.h"
NSString * const NSTaskRACSupportErrorDomain = @"NSTaskRACSupportErrorDomain";
@@ -54,81 +55,92 @@ - (RACSignal *)rac_completion {
return signal;
}
-- (RACCancelableSignal *)rac_run {
+- (RACSignal *)rac_run {
return [self rac_runWithScheduler:[RACScheduler immediateScheduler]];
}
-- (RACCancelableSignal *)rac_runWithScheduler:(RACScheduler *)scheduler {
+- (RACSignal *)rac_runWithScheduler:(RACScheduler *)scheduler {
NSParameterAssert(scheduler != nil);
+ @weakify(self);
+ return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
+ __block uint32_t volatile canceled = 0;
+ RACDisposable *disposable = [[self rac_launchWithScheduler:scheduler cancelationToken:&canceled] subscribe:subscriber];
+ return [RACDisposable disposableWithBlock:^{
+ @strongify(self);
+ OSAtomicOr32Barrier(1, &canceled);
+ [self terminate];
+ [disposable dispose];
+ }];
+ }] replayLazily];
+}
+
+- (RACSignal *)rac_launchWithScheduler:(RACScheduler *)scheduler cancelationToken:(volatile uint32_t *)cancelationToken {
RACReplaySubject *subject = [RACReplaySubject subject];
subject.name = [NSString stringWithFormat:@"%@ -rac_runWithScheduler: %@", self, scheduler];
-
- __block BOOL canceled = NO;
+
[RACScheduler.mainThreadScheduler schedule:^{
NSMutableData * (^aggregateData)(NSMutableData *, NSData *) = ^(NSMutableData *running, NSData *next) {
[running appendData:next];
return running;
};
-
+
// TODO: should we aggregate the data on the given scheduler too?
- RACConnectableSignal *outputSignal = [[self.rac_standardOutput aggregateWithStart:[NSMutableData data] combine:aggregateData] publish];
+ RACMulticastConnection *outputConnection = [[self.rac_standardOutput aggregateWithStart:[NSMutableData data] combine:aggregateData] publish];
__block NSData *outputData = nil;
- [outputSignal subscribeNext:^(NSData *accumulatedData) {
+ [outputConnection.signal subscribeNext:^(NSData *accumulatedData) {
outputData = accumulatedData;
}];
-
- RACConnectableSignal *errorSignal = [[self.rac_standardError aggregateWithStart:[NSMutableData data] combine:aggregateData] publish];
+
+ RACMulticastConnection *errorConnection = [[self.rac_standardError aggregateWithStart:[NSMutableData data] combine:aggregateData] publish];
__block NSData *errorData = nil;
- [errorSignal subscribeNext:^(NSData *accumulatedData) {
+ [errorConnection.signal subscribeNext:^(NSData *accumulatedData) {
errorData = accumulatedData;
}];
-
+
// wait until termination's signaled and output and error are done
- [[RACSignal merge:@[ outputSignal, errorSignal, self.rac_completion ]] subscribeNext:^(id _) {
+ [[RACSignal merge:@[ outputConnection.signal, errorConnection.signal, self.rac_completion ]] subscribeNext:^(id _) {
// nothing
} completed:^{
- if(canceled) return;
-
+ if (*cancelationToken == 1) return;
+
[scheduler schedule:^{
- if(canceled) return;
-
- if([self terminationStatus] == 0) {
+ if (*cancelationToken == 1) return;
+
+ if (self.terminationStatus == 0) {
[subject sendNext:outputData];
[subject sendCompleted];
} else {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
- if(outputData != nil) {
- [userInfo setObject:outputData forKey:NSTaskRACSupportOutputData];
-
+ if (outputData != nil) {
+ userInfo[NSTaskRACSupportOutputData] = outputData;
+
NSString *string = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
- if(string != nil) [userInfo setObject:string forKey:NSTaskRACSupportOutputString];
+ if(string != nil) userInfo[NSTaskRACSupportOutputString] = string;
}
- if(errorData != nil) {
- [userInfo setObject:errorData forKey:NSTaskRACSupportErrorData];
-
+
+ if (errorData != nil) {
+ userInfo[NSTaskRACSupportErrorData] = errorData;
+
NSString *string = [[NSString alloc] initWithData:errorData encoding:NSUTF8StringEncoding];
- if(string != nil) [userInfo setObject:string forKey:NSTaskRACSupportErrorString];
+ if(string != nil) userInfo[NSTaskRACSupportErrorString] = string;
}
- if([self arguments] != nil) [userInfo setObject:[self arguments] forKey:NSTaskRACSupportTaskArguments];
- [userInfo setObject:self forKey:NSTaskRACSupportTask];
+
+ if (self.arguments != nil) userInfo[NSTaskRACSupportTaskArguments] = self.arguments;
+
+ userInfo[NSTaskRACSupportTask] = self;
[subject sendError:[NSError errorWithDomain:NSTaskRACSupportErrorDomain code:NSTaskRACSupportNonZeroTerminationStatus userInfo:userInfo]];
}
}];
}];
-
- [outputSignal connect];
- [errorSignal connect];
-
+
+ [outputConnection connect];
+ [errorConnection connect];
+
[self launch];
}];
-
- __weak NSTask *weakSelf = self;
- return [subject asCancelableWithBlock:^{
- NSTask *strongSelf = weakSelf;
- canceled = YES;
- [strongSelf terminate];
- }];
+
+ return subject;
}
@end
View
55 ReactiveCocoaFramework/ReactiveCocoa.xcodeproj/project.pbxproj
@@ -85,12 +85,12 @@
889D0A8015974B2A00F833E3 /* RACSubjectSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 889D0A7F15974B2A00F833E3 /* RACSubjectSpec.m */; };
88A0B6D2165B2B09005DE8F3 /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = 888439A21634E10D00DED0DB /* RACBlockTrampoline.m */; };
88A0B6D3165B2B77005DE8F3 /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = 88FC735316114F9C00F8A774 /* RACSubscriptingAssignmentTrampoline.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 88A5F4FB156B3FCB009E49DC /* RACCancelableSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88A5F4F9156B3FCB009E49DC /* RACCancelableSignal.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 88A5F4FC156B3FCB009E49DC /* RACCancelableSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A5F4FA156B3FCB009E49DC /* RACCancelableSignal.m */; };
- 88A5F4FE156B4301009E49DC /* RACCancelableSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A5F4FA156B3FCB009E49DC /* RACCancelableSignal.m */; };
88B76F8E153726B00053EAE2 /* RACTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = 88B76F8C153726B00053EAE2 /* RACTuple.h */; settings = {ATTRIBUTES = (Public, ); }; };
88B76F8F153726B00053EAE2 /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B76F8D153726B00053EAE2 /* RACTuple.m */; };
- 88CA0C3116235A9200CA30BB /* RACConnectableSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88CA0C3016235A9200CA30BB /* RACConnectableSignalSpec.m */; };
+ 88C5A0241692460A0045EF05 /* RACMulticastConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 88C5A0231692460A0045EF05 /* RACMulticastConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 88C5A026169246140045EF05 /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C5A025169246140045EF05 /* RACMulticastConnection.m */; };
+ 88C5A027169246140045EF05 /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C5A025169246140045EF05 /* RACMulticastConnection.m */; };
+ 88C5A02916924BFC0045EF05 /* RACMulticastConnectionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C5A02816924BFC0045EF05 /* RACMulticastConnectionSpec.m */; };
88CDF7DE15000FCF00163A9F /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88CDF7DD15000FCF00163A9F /* SenTestingKit.framework */; };
88CDF7DF15000FCF00163A9F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88CDF7BF15000FCE00163A9F /* Cocoa.framework */; };
88CDF7E715000FCF00163A9F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 88CDF7E515000FCF00163A9F /* InfoPlist.strings */; };
@@ -105,7 +105,6 @@
88F440BA153DAD570097B4C3 /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 882093EA1501E6EE00796685 /* RACCommand.m */; };
88F440BC153DAD5A0097B4C3 /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = 88CDF7FB150019CA00163A9F /* RACSubscriber.m */; };
88F440BD153DAD5C0097B4C3 /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = 88977C3D1512914A00A09EC5 /* RACSignal.m */; };
- 88F440BF153DAD600097B4C3 /* RACConnectableSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F5870115361BCD0084BD32 /* RACConnectableSignal.m */; };
88F440C0153DAD630097B4C3 /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = 880B9175150B09190008488E /* RACSubject.m */; };
88F440C1153DAD640097B4C3 /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D4AB3D1510F6C30011494F /* RACReplaySubject.m */; };
88F440C3153DAD690097B4C3 /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = 883A84D91513964B006DB4C7 /* RACBehaviorSubject.m */; };
@@ -123,8 +122,6 @@
88F44263153DC2C70097B4C3 /* UIControl+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F44260153DC0450097B4C3 /* UIControl+RACSignalSupport.m */; };
88F44266153DCAC50097B4C3 /* UITextField+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F44264153DCAC50097B4C3 /* UITextField+RACSignalSupport.h */; };
88F44267153DCAC50097B4C3 /* UITextField+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F44265153DCAC50097B4C3 /* UITextField+RACSignalSupport.m */; };
- 88F5870215361BCD0084BD32 /* RACConnectableSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F5870015361BCD0084BD32 /* RACConnectableSignal.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 88F5870315361BCD0084BD32 /* RACConnectableSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F5870115361BCD0084BD32 /* RACConnectableSignal.m */; };
88F70068152D2D7B00B32771 /* NSObject+RACBindings.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F70066152D2D7B00B32771 /* NSObject+RACBindings.h */; settings = {ATTRIBUTES = (Public, ); }; };
88F70069152D2D7B00B32771 /* NSObject+RACBindings.m in Sources */ = {isa = PBXBuildFile; fileRef = 88F70067152D2D7B00B32771 /* NSObject+RACBindings.m */; };
88FC735616114F9C00F8A774 /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = 88FC735316114F9C00F8A774 /* RACSubscriptingAssignmentTrampoline.h */; };
@@ -137,11 +134,8 @@
90AF46D01625537D0054F8A0 /* RACSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = 88CDF7FA150019CA00163A9F /* RACSubscriber.h */; };
90AF46D11625537D0054F8A0 /* RACSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88CDF80415001CA800163A9F /* RACSignal.h */; };
90AF46D21625537D0054F8A0 /* RACSignal+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 88977C58151296D600A09EC5 /* RACSignal+Private.h */; };
- 90AF46D31625537D0054F8A0 /* RACConnectableSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F5870015361BCD0084BD32 /* RACConnectableSignal.h */; };
- 90AF46D41625537D0054F8A0 /* RACConnectableSignal+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F5870515361C170084BD32 /* RACConnectableSignal+Private.h */; };
+ 90AF46D41625537D0054F8A0 /* RACMulticastConnection+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F5870515361C170084BD32 /* RACMulticastConnection+Private.h */; };
90AF46D51625537D0054F8A0 /* RACGroupedSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 886F70281551CF920045D68B /* RACGroupedSignal.h */; };
- 90AF46D61625537D0054F8A0 /* RACCancelableSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88A5F4F9156B3FCB009E49DC /* RACCancelableSignal.h */; };
- 90AF46D71625537D0054F8A0 /* RACCancelableSignal+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 88A5F4FD156B3FED009E49DC /* RACCancelableSignal+Private.h */; };
90AF46D81625537D0054F8A0 /* RACSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = 880B9174150B09190008488E /* RACSubject.h */; };
90AF46D91625537D0054F8A0 /* RACReplaySubject.h in Headers */ = {isa = PBXBuildFile; fileRef = 88D4AB3C1510F6C30011494F /* RACReplaySubject.h */; };
90AF46DB1625537D0054F8A0 /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = 883A84D81513964B006DB4C7 /* RACBehaviorSubject.h */; };
@@ -411,12 +405,11 @@
88977C3D1512914A00A09EC5 /* RACSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSignal.m; sourceTree = "<group>"; };
88977C58151296D600A09EC5 /* RACSignal+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RACSignal+Private.h"; sourceTree = "<group>"; };
889D0A7F15974B2A00F833E3 /* RACSubjectSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubjectSpec.m; sourceTree = "<group>"; };
- 88A5F4F9156B3FCB009E49DC /* RACCancelableSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACCancelableSignal.h; sourceTree = "<group>"; };
- 88A5F4FA156B3FCB009E49DC /* RACCancelableSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RACCancelableSignal.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
- 88A5F4FD156B3FED009E49DC /* RACCancelableSignal+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "RACCancelableSignal+Private.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
88B76F8C153726B00053EAE2 /* RACTuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTuple.h; sourceTree = "<group>"; };
88B76F8D153726B00053EAE2 /* RACTuple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTuple.m; sourceTree = "<group>"; };
- 88CA0C3016235A9200CA30BB /* RACConnectableSignalSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACConnectableSignalSpec.m; sourceTree = "<group>"; };
+ 88C5A0231692460A0045EF05 /* RACMulticastConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACMulticastConnection.h; sourceTree = "<group>"; };
+ 88C5A025169246140045EF05 /* RACMulticastConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACMulticastConnection.m; sourceTree = "<group>"; };
+ 88C5A02816924BFC0045EF05 /* RACMulticastConnectionSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACMulticastConnectionSpec.m; sourceTree = "<group>"; };
88CDF7BF15000FCE00163A9F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
88CDF7C215000FCE00163A9F /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
88CDF7C315000FCE00163A9F /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
@@ -446,9 +439,7 @@
88F44260153DC0450097B4C3 /* UIControl+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+RACSignalSupport.m"; sourceTree = "<group>"; };
88F44264153DCAC50097B4C3 /* UITextField+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITextField+RACSignalSupport.h"; sourceTree = "<group>"; };
88F44265153DCAC50097B4C3 /* UITextField+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextField+RACSignalSupport.m"; sourceTree = "<group>"; };
- 88F5870015361BCD0084BD32 /* RACConnectableSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RACConnectableSignal.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
- 88F5870115361BCD0084BD32 /* RACConnectableSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RACConnectableSignal.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
- 88F5870515361C170084BD32 /* RACConnectableSignal+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "RACConnectableSignal+Private.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+ 88F5870515361C170084BD32 /* RACMulticastConnection+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "RACMulticastConnection+Private.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
88F70066152D2D7B00B32771 /* NSObject+RACBindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACBindings.h"; sourceTree = "<group>"; };
88F70067152D2D7B00B32771 /* NSObject+RACBindings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACBindings.m"; sourceTree = "<group>"; };
88FC735316114F9C00F8A774 /* RACSubscriptingAssignmentTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubscriptingAssignmentTrampoline.h; sourceTree = "<group>"; };
@@ -733,10 +724,9 @@
8851A38C1616295D0050D47F /* RACPropertySignalExamples.h */,
8851A38D1616295D0050D47F /* RACPropertySignalExamples.m */,
8801E7501644BDE200A155FE /* NSObjectRACLiftingSpec.m */,
- 88CA0C3016235A9200CA30BB /* RACConnectableSignalSpec.m */,
886CEACC163DE669007632D1 /* RACBlockTrampolineSpec.m */,
882CCA1D15F1564D00937D6E /* RACCommandSpec.m */,
- 88CA0C3016235A9200CA30BB /* RACConnectableSignalSpec.m */,
+ 88C5A02816924BFC0045EF05 /* RACMulticastConnectionSpec.m */,
866557A51557086B00B39EB5 /* RACExtensionsSpec.m */,
D041376815D2281C004BBF80 /* RACKVOWrapperSpec.m */,
8851A38C1616295D0050D47F /* RACPropertySignalExamples.h */,
@@ -948,14 +938,11 @@
88977C3D1512914A00A09EC5 /* RACSignal.m */,
D0D910CC15F915BD00AD2DDA /* RACSignal+Operations.h */,
D0D910CD15F915BD00AD2DDA /* RACSignal+Operations.m */,
- 88F5870015361BCD0084BD32 /* RACConnectableSignal.h */,
- 88F5870515361C170084BD32 /* RACConnectableSignal+Private.h */,
- 88F5870115361BCD0084BD32 /* RACConnectableSignal.m */,
+ 88C5A0231692460A0045EF05 /* RACMulticastConnection.h */,
+ 88F5870515361C170084BD32 /* RACMulticastConnection+Private.h */,
+ 88C5A025169246140045EF05 /* RACMulticastConnection.m */,
886F70281551CF920045D68B /* RACGroupedSignal.h */,
886F70291551CF920045D68B /* RACGroupedSignal.m */,
- 88A5F4F9156B3FCB009E49DC /* RACCancelableSignal.h */,
- 88A5F4FD156B3FED009E49DC /* RACCancelableSignal+Private.h */,
- 88A5F4FA156B3FCB009E49DC /* RACCancelableSignal.m */,
D0D486FC164253C400DD7605 /* Subjects */,
);
name = Signals;
@@ -1031,7 +1018,6 @@
88037FC21505646C001A5B19 /* NSButton+RACCommandSupport.h in Headers */,
880B9176150B09190008488E /* RACSubject.h in Headers */,
88F440D3153DADEA0097B4C3 /* NSObject+RACAppKitBindings.h in Headers */,
- 88A5F4FB156B3FCB009E49DC /* RACCancelableSignal.h in Headers */,
88D4AB3E1510F6C30011494F /* RACReplaySubject.h in Headers */,
883A84DA1513964B006DB4C7 /* RACBehaviorSubject.h in Headers */,
883A84DF1513B5EC006DB4C7 /* RACDisposable.h in Headers */,
@@ -1040,7 +1026,6 @@
884476E4152367D100958F44 /* RACScopedDisposable.h in Headers */,
88F70068152D2D7B00B32771 /* NSObject+RACBindings.h in Headers */,
8857BB82152A27A9009804CC /* NSObject+RACKVOWrapper.h in Headers */,
- 88F5870215361BCD0084BD32 /* RACConnectableSignal.h in Headers */,
88E2C6B4153C771C00C7493C /* RACScheduler.h in Headers */,
88B76F8E153726B00053EAE2 /* RACTuple.h in Headers */,
886CEAE2163DE942007632D1 /* NSObject+RACLifting.h in Headers */,
@@ -1058,6 +1043,7 @@
D0E967991641F0AF00FCFF06 /* NSObject+RACExtensions.h in Headers */,
88A0B6D3165B2B77005DE8F3 /* RACSubscriptingAssignmentTrampoline.h in Headers */,
D0D487011642550100DD7605 /* RACStream.h in Headers */,
+ 88C5A0241692460A0045EF05 /* RACMulticastConnection.h in Headers */,
881E86A21669304800667F7B /* RACCompoundDisposable.h in Headers */,
888439A31634E10D00DED0DB /* RACBlockTrampoline.h in Headers */,
887ACDA7165878A8009190AD /* NSInvocation+RACTypeParsing.h in Headers */,
@@ -1094,11 +1080,8 @@
90AF46D01625537D0054F8A0 /* RACSubscriber.h in Headers */,
90AF46D11625537D0054F8A0 /* RACSignal.h in Headers */,
90AF46D21625537D0054F8A0 /* RACSignal+Private.h in Headers */,
- 90AF46D31625537D0054F8A0 /* RACConnectableSignal.h in Headers */,
- 90AF46D41625537D0054F8A0 /* RACConnectableSignal+Private.h in Headers */,
+ 90AF46D41625537D0054F8A0 /* RACMulticastConnection+Private.h in Headers */,
90AF46D51625537D0054F8A0 /* RACGroupedSignal.h in Headers */,
- 90AF46D61625537D0054F8A0 /* RACCancelableSignal.h in Headers */,
- 90AF46D71625537D0054F8A0 /* RACCancelableSignal+Private.h in Headers */,
90AF46D81625537D0054F8A0 /* RACSubject.h in Headers */,
90AF46D91625537D0054F8A0 /* RACReplaySubject.h in Headers */,
90AF46DB1625537D0054F8A0 /* RACBehaviorSubject.h in Headers */,
@@ -1343,12 +1326,10 @@
8857BB7F152A2747009804CC /* NSObject+RACExtensions.m in Sources */,
8867D5FA152BDAC300321BD5 /* RACSwizzling.m in Sources */,
88F70069152D2D7B00B32771 /* NSObject+RACBindings.m in Sources */,
- 88F5870315361BCD0084BD32 /* RACConnectableSignal.m in Sources */,
88B76F8F153726B00053EAE2 /* RACTuple.m in Sources */,
88E2C6B5153C771C00C7493C /* RACScheduler.m in Sources */,
88F440D4153DADEA0097B4C3 /* NSObject+RACAppKitBindings.m in Sources */,
886F702B1551CF920045D68B /* RACGroupedSignal.m in Sources */,
- 88A5F4FC156B3FCB009E49DC /* RACCancelableSignal.m in Sources */,
A1FCC374156754A7008C9686 /* RACObjCRuntime.m in Sources */,
8809D6F015B1F1EE007E32AA /* JRSwizzle.m in Sources */,
D0DFBCCE15DD6D40009DADB3 /* RACBacktrace.m in Sources */,
@@ -1375,6 +1356,7 @@
881E87AE16695C5600667F7B /* RACQueueScheduler.m in Sources */,
881E87B416695EDF00667F7B /* RACImmediateScheduler.m in Sources */,
881E87C61669636000667F7B /* RACSubscriptionScheduler.m in Sources */,
+ 88C5A026169246140045EF05 /* RACMulticastConnection.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1392,7 +1374,6 @@
88FC735B16114FFB00F8A774 /* RACSubscriptingAssignmentTrampolineSpec.m in Sources */,
8851A38B16161D500050D47F /* NSObjectRACPropertySubscribingSpec.m in Sources */,
8851A38E1616295D0050D47F /* RACPropertySignalExamples.m in Sources */,
- 88CA0C3116235A9200CA30BB /* RACConnectableSignalSpec.m in Sources */,
D0D487061642651400DD7605 /* RACSequenceSpec.m in Sources */,
D0487AB3164314430085D890 /* RACStreamExamples.m in Sources */,
D0C70F90164337A2007027B4 /* RACSequenceAdditionsSpec.m in Sources */,
@@ -1411,6 +1392,7 @@
D0700F4C1672994D00D7CD30 /* NSNotificationCenterRACSupportSpec.m in Sources */,
D02221621678910900DBD031 /* RACTupleSpec.m in Sources */,
D0870C6F16884A0600D0E11D /* RACBacktraceSpec.m in Sources */,
+ 88C5A02916924BFC0045EF05 /* RACMulticastConnectionSpec.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1419,7 +1401,6 @@
buildActionMask = 2147483647;
files = (
8882D4601673B0450080E7CD /* RACBlockTrampoline.m in Sources */,
- 88F440BF153DAD600097B4C3 /* RACConnectableSignal.m in Sources */,
88F440B6153DAD300097B4C3 /* NSObject+RACExtensions.m in Sources */,
88F440BA153DAD570097B4C3 /* RACCommand.m in Sources */,
88F440B7153DAD320097B4C3 /* RACSwizzling.m in Sources */,
@@ -1431,7 +1412,6 @@
88F440C1153DAD640097B4C3 /* RACReplaySubject.m in Sources */,
88F440C0153DAD630097B4C3 /* RACSubject.m in Sources */,
88F440C6153DAD6E0097B4C3 /* RACScopedDisposable.m in Sources */,
- 88A5F4FE156B4301009E49DC /* RACCancelableSignal.m in Sources */,
88F440C3153DAD690097B4C3 /* RACBehaviorSubject.m in Sources */,
88F440CD153DAD820097B4C3 /* NSObject+RACBindings.m in Sources */,
88F440C9153DAD740097B4C3 /* RACUnit.m in Sources */,
@@ -1470,6 +1450,7 @@
881E87AF16695C5600667F7B /* RACQueueScheduler.m in Sources */,
881E87B516695EDF00667F7B /* RACImmediateScheduler.m in Sources */,
881E87C71669636000667F7B /* RACSubscriptionScheduler.m in Sources */,
+ 88C5A027169246140045EF05 /* RACMulticastConnection.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
8 ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACLifting.m
@@ -11,7 +11,7 @@
#import "NSInvocation+RACTypeParsing.h"
#import "NSObject+RACPropertySubscribing.h"
#import "RACBlockTrampoline.h"
-#import "RACConnectableSignal.h"
+#import "RACMulticastConnection.h"
#import "RACReplaySubject.h"
#import "RACSignal+Operations.h"
#import "RACTuple.h"
@@ -20,12 +20,12 @@
@implementation NSObject (RACLifting)
- (RACSignal *)rac_liftSignals:(NSArray *)signals withReducingInvocation:(id (^)(RACTuple *))reduceBlock {
- RACConnectableSignal *signal = [[[RACSignal combineLatest:signals] map:reduceBlock] multicast:[RACReplaySubject replaySubjectWithCapacity:1]];
+ RACMulticastConnection *connection = [[[RACSignal combineLatest:signals] map:reduceBlock] multicast:[RACReplaySubject replaySubjectWithCapacity:1]];
- RACDisposable *disposable = [signal connect];
+ RACDisposable *disposable = [connection connect];
[self rac_addDeallocDisposable:disposable];
- return signal;
+ return connection.signal;
}
- (RACSignal *)rac_liftSelector:(SEL)selector withObjects:(id)arg, ... {
View
17 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal+Private.h
@@ -1,17 +0,0 @@
-//
-// RACCancelableSignal+Private.h
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 5/21/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACCancelableSignal.h"
-
-@interface RACCancelableSignal ()
-
-// Defaults to using a RACReplaySubject.
-+ (instancetype)cancelableSignalSourceSignal:(RACSignal *)sourceSignal withBlock:(void (^)(void))block;
-+ (instancetype)cancelableSignalSourceSignal:(RACSignal *)sourceSignal subject:(RACSubject *)subject withBlock:(void (^)(void))block;
-
-@end
View
22 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal.h
@@ -1,22 +0,0 @@
-//
-// RACCancelableSignal.h
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 5/21/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACConnectableSignal.h"
-
-// Cancelable signal represents an operation that can be canceled. Canceling
-// means that the signal is no longer valid. It will tear down all its
-// subscribers.
-//
-// Note that cancelation is different from disposing of a subscription.
-// Canceling invalidates and tears down the whole signal, whereas disposal just
-// closes a particular subscription.
-@interface RACCancelableSignal : RACConnectableSignal
-
-- (void)cancel;
-
-@end
View
50 ReactiveCocoaFramework/ReactiveCocoa/RACCancelableSignal.m
@@ -1,50 +0,0 @@
-//
-// RACCancelableSignal.m
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 5/21/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACCancelableSignal.h"
-#import "RACSignal+Private.h"
-#import "RACConnectableSignal+Private.h"
-#import "RACReplaySubject.h"
-
-@interface RACCancelableSignal ()
-@property (nonatomic, copy) void (^cancelBlock)(void);
-@end
-
-@implementation RACCancelableSignal
-
-#pragma mark RACSignal
-
-- (void)tearDown {
- @synchronized(self) {
- if(self.cancelBlock != NULL) {
- self.cancelBlock();
- self.cancelBlock = NULL;
- }
- }
-
- [super tearDown];
-}
-
-#pragma mark API
-
-+ (instancetype)cancelableSignalSourceSignal:(RACSignal *)sourceSignal withBlock:(void (^)(void))block {
- return [self cancelableSignalSourceSignal:sourceSignal subject:[RACReplaySubject subject] withBlock:block];
-}
-
-+ (instancetype)cancelableSignalSourceSignal:(RACSignal *)sourceSignal subject:(RACSubject *)subject withBlock:(void (^)(void))block {
- RACCancelableSignal *signal = [self connectableSignalWithSourceSignal:sourceSignal subject:subject];
- [signal connect];
- signal.cancelBlock = block;
- return signal;
-}
-
-- (void)cancel {
- [self tearDown];
-}
-
-@end
View
2  ReactiveCocoaFramework/ReactiveCocoa/RACCompoundDisposable.h
@@ -25,7 +25,7 @@
+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables;
// Adds the given disposable. If the receiving disposable has already been
-// disposed of, the given disposable is disposed immediately.
+// disposed of, the given disposable is disposed immediately. Thread-safe.
//
// disposable - The disposable to add. Cannot be nil.
- (void)addDisposable:(RACDisposable *)disposable;
View
17 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal+Private.h
@@ -1,17 +0,0 @@
-//
-// RACConnectableSignal+Private.h
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 4/11/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACConnectableSignal.h"
-
-@class RACSubject;
-
-@interface RACConnectableSignal ()
-
-+ (instancetype)connectableSignalWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject;
-
-@end
View
29 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal.h
@@ -1,29 +0,0 @@
-//
-// RACConnectableSignal.h
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 4/11/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACSignal.h"
-
-// A connectable signal encapsulates the idea of sharing one subscription to a
-// signal to many subscribers. This is most often needed if the subscription to
-// the underlying signal involves side-effects or shouldn't be called more than
-// once.
-//
-// Note that you shouldn't create RACConnectableSignal manually. Instead use
-// -[RACSignal publish] or -[RACSignal multicast:].
-@interface RACConnectableSignal : RACSignal
-
-// Connect to the underlying signal. Calling this multiple times does nothing
-// but return the existing connection's disposable.
-- (RACDisposable *)connect;
-
-// Creates and returns a signal that calls -connect when the receiver gets its
-// first subscription. Once all its subscribers are gone, subsequent
-// subscriptions will reconnect to the receiver.
-- (RACSignal *)autoconnect;
-
-@end
View
73 ReactiveCocoaFramework/ReactiveCocoa/RACConnectableSignal.m
@@ -1,73 +0,0 @@
-//
-// RACConnectableSignal.m
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 4/11/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACConnectableSignal.h"
-#import "RACConnectableSignal+Private.h"
-#import "RACSignal+Private.h"
-#import "RACSubscriber.h"
-#import "RACSubject.h"
-#import "RACDisposable.h"
-
-@interface RACConnectableSignal ()
-@property (nonatomic, strong) RACSignal *sourceSignal;
-@property (nonatomic, strong) RACSubject *subject;
-@property (nonatomic, strong) RACDisposable *disposable;
-@end
-
-@implementation RACConnectableSignal
-
-#pragma mark RACSignal
-
-- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
- return [self.subject subscribe:subscriber];
-}
-
-#pragma mark API
-
-+ (instancetype)connectableSignalWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
- RACConnectableSignal *signal = [[self alloc] init];
- signal.sourceSignal = source;
- signal.subject = subject;
- return signal;
-}
-
-- (RACDisposable *)connect {
- @synchronized(self) {
- if (self.disposable == nil) {
- self.disposable = [self.sourceSignal subscribe:self.subject];
- }
-
- return self.disposable;
- }
-}
-
-- (RACSignal *)autoconnect {
- return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
- RACDisposable *subscriptionDisposable = [self subscribe:subscriber];
-
- [self connect];
-
- return [RACDisposable disposableWithBlock:^{
- [subscriptionDisposable dispose];
-
- BOOL noSubscribers = NO;
- @synchronized(self.subject.subscribers) {
- noSubscribers = self.subject.subscribers.count < 1;
- }
-
- if (noSubscribers) {
- @synchronized(self) {
- [self.disposable dispose];
- self.disposable = nil;
- }
- }
- }];
- } name:@"[%@] -autoconnect", self.name];
-}
-
-@end
View
17 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection+Private.h
@@ -0,0 +1,17 @@
+//
+// RACMulticastConnection+Private.h
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+#import "RACMulticastConnection.h"
+
+@class RACSubject;
+
+@interface RACMulticastConnection ()
+
+- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject;
+
+@end
View
46 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.h
@@ -0,0 +1,46 @@
+//
+// RACMulticastConnection.h
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+@class RACSignal;
+@class RACDisposable;
+
+// A multicast connection encapsulates the idea of sharing one subscription to a
+// signal to many subscribers. This is most often needed if the subscription to
+// the underlying signal involves side-effects or shouldn't be called more than
+// once.
+//
@jspahrsummers Owner

We should add another paragraph here, talking about how to activate the receiver's signal (and what it means to do so).

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+// The multicasted signal is only subscribed to when
+// -[RACMulticastConnection connect] is called. Until that happens, no values
+// will be sent on `signal`. See -[RACMulticastConnection autoconnect] for how
+// -[RACMulticastConnection connect] can be called automatically.
+//
+// Note that you shouldn't create RACMulticastConnection manually. Instead use
+// -[RACSignal publish] or -[RACSignal multicast:].
+@interface RACMulticastConnection : NSObject
+
+// The multicasted signal.
+@property (nonatomic, strong, readonly) RACSignal *signal;
+
+// Connect to the underlying signal by subscribing to it. Calling this multiple
+// times does nothing but return the existing connection's disposable.
+//
+// Returns the disposable for the subscription to the multicasted signal.
+- (RACDisposable *)connect;
+
+// Connects to the underlying signal when the returned signal is first
+// subscribed to, and disposes of the subscription to the multicasted signal
+// when the returned signal has no subscribers.
+//
+// If new subscribers show up after being disposed, they'll subscribe and then
+// be immediately disposed of. The returned signal will never re-connect to the
+// multicasted signal.
+//
+// Returns the autoconnecting signal.
+- (RACSignal *)autoconnect;
+
+@end
View
81 ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.m
@@ -0,0 +1,81 @@
+//
+// RACMulticastConnection.m
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 4/11/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+#import "RACMulticastConnection.h"
+#import "RACMulticastConnection+Private.h"
+#import "RACSubject.h"
+#import "RACCompoundDisposable.h"
+#import "RACSignal+Private.h"
+
+@interface RACMulticastConnection () {
+ RACSubject *_signal;
+}
+
+@property (nonatomic, readonly, strong) RACSignal *sourceSignal;
@jspahrsummers Owner

Can you please document what needs synchronization here?

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+@property (nonatomic, readonly, strong) RACCompoundDisposable *disposable;
+
+// Should only be used while synchronized on self.
+@property (nonatomic, assign) BOOL hasConnected;
+@end
+
+@implementation RACMulticastConnection
+
+#pragma mark Lifecycle
+
+- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
+ NSParameterAssert(source != nil);
+ NSParameterAssert(subject != nil);
+
+ self = [super init];
+ if (self == nil) return nil;
+
+ _disposable = [RACCompoundDisposable compoundDisposable];
+ _sourceSignal = source;
+ _signal = subject;
+
+ return self;
+}
+
+#pragma mark Connecting
+
+- (RACDisposable *)connect {
+ BOOL shouldConnect = NO;
+ @synchronized(self) {
+ if (!self.hasConnected) {
+ shouldConnect = YES;
+ self.hasConnected = YES;
+ }
+ }
+
+ if (shouldConnect) {
+ RACDisposable *sourceDisposable = [self.sourceSignal subscribe:_signal];
+ if (sourceDisposable != nil) [self.disposable addDisposable:sourceDisposable];
+ }
+
+ return self.disposable;
+}
+
+- (RACSignal *)autoconnect {
+ return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
+ RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
+ if (subscriptionDisposable != nil) [self.disposable addDisposable:subscriptionDisposable];
+ [self connect];
+
+ return [RACDisposable disposableWithBlock:^{
+ [subscriptionDisposable dispose];
+
+ @synchronized(self.signal.subscribers) {
+ if (self.signal.subscribers.count < 1) {
+ [self.disposable dispose];
+ }
+ }
+ }];
+ } name:@"[%@] -autoconnect", self.signal.name];
+}
+
+@end
View
34 ReactiveCocoaFramework/ReactiveCocoa/RACSignal+Operations.h
@@ -18,8 +18,7 @@ typedef enum {
typedef NSInteger RACSignalError;
-@class RACCancelableSignal;
-@class RACConnectableSignal;
+@class RACMulticastConnection;
@class RACDisposable;
@class RACScheduler;
@class RACSequence;
@@ -232,14 +231,27 @@ typedef NSInteger RACSignalError;
// block.
@property (nonatomic, strong, readonly) RACSequence *sequence;
-// Creates and returns a connectable signal. This allows you to share a single
+// Creates and returns a multicast connection. This allows you to share a single
// subscription to the underlying signal.
-- (RACConnectableSignal *)publish;
+- (RACMulticastConnection *)publish;
-// Creates and returns a connectable signal that pushes values into the given
+// Creates and returns a multicast connection that pushes values into the given
// subject. This allows you to share a single subscription to the underlying
// signal.
-- (RACConnectableSignal *)multicast:(RACSubject *)subject;
+- (RACMulticastConnection *)multicast:(RACSubject *)subject;
+
+// Multicasts the signal to a RACReplaySubject and immediately connects to the
+// resulting RACMulticastConnection.
+//
+// Returns the connected, multicasted signal.
+- (RACSignal *)replay;
+
+// Multicasts the signal to a RACReplaySubject and calls -autoconnect on the
+// resulting RACMulticastConnection. This means the signal will subscribe to
+// the multicasted signal only when it receives its first subscription.
+//
+// Returns the autoconnected, multicasted signal.
+- (RACSignal *)replayLazily;
// Sends an error after `interval` seconds if the source doesn't complete
// before then. The timeout is scheduled on the default priority global queue.
@@ -292,16 +304,6 @@ typedef NSInteger RACSignalError;
// Resubscribes to the receiving signal if an error occurs.
- (RACSignal *)retry;
-// Creates a cancelable signal multicasted to the given subject with the given
-// cancelation block.
-- (RACCancelableSignal *)asCancelableToSubject:(RACSubject *)subject withBlock:(void (^)(void))block;
-
-// Creates a cancelable signal with the given cancelation block.
-- (RACCancelableSignal *)asCancelableWithBlock:(void (^)(void))block;
-
-// Creates a cancelable signal.
-- (RACCancelableSignal *)asCancelable;
-
// Sends the latest value from the receiver only when `sampler` sends a value.
// The returned signal could repeat values if `sampler` fires more often than
// the receiver.
View
53 ReactiveCocoaFramework/ReactiveCocoa/RACSignal+Operations.m
@@ -13,9 +13,7 @@
#import "NSObject+RACPropertySubscribing.h"
#import "RACBehaviorSubject.h"
#import "RACBlockTrampoline.h"
-#import "RACCancelableSignal+Private.h"
#import "RACCompoundDisposable.h"
-#import "RACConnectableSignal+Private.h"
#import "RACDisposable.h"
#import "RACGroupedSignal.h"
#import "RACMaybe.h"
@@ -26,6 +24,8 @@
#import "RACSubscriber.h"
#import "RACTuple.h"
#import "RACUnit.h"
+#import "RACMulticastConnection+Private.h"
+#import "RACReplaySubject.h"
#import <libkern/OSAtomic.h>
#import <objc/runtime.h>
@@ -918,15 +918,30 @@ - (RACSequence *)sequence {
return sequence;
}
-- (RACConnectableSignal *)publish {
- RACConnectableSignal *signal = [self multicast:[RACSubject subject]];
- signal.name = [NSString stringWithFormat:@"[%@] -publish", self.name];
- return signal;
+- (RACMulticastConnection *)publish {
+ RACSubject *subject = [RACSubject subject];
+ RACMulticastConnection *connection = [self multicast:subject];
+ subject.name = [NSString stringWithFormat:@"[%@] -publish", self.name];
+ return connection;
+}
+
+- (RACMulticastConnection *)multicast:(RACSubject *)subject {
+ RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
+ connection.signal.name = [NSString stringWithFormat:@"[%@] -multicast: %@", self.name, subject];
+ return connection;
}
-- (RACConnectableSignal *)multicast:(RACSubject *)subject {
- RACConnectableSignal *signal = [RACConnectableSignal connectableSignalWithSourceSignal:self subject:subject];
- signal.name = [NSString stringWithFormat:@"[%@] -multicast: %@", self.name, subject];
+- (RACSignal *)replay {
+ RACReplaySubject *subject = [RACReplaySubject subject];
+ RACMulticastConnection *connection = [self multicast:subject];
+ subject.name = [NSString stringWithFormat:@"[%@] -replay", self.name];
+ [connection connect];
+ return connection.signal;
+}
+
+- (RACSignal *)replayLazily {
+ RACSignal *signal = [[self multicast:[RACReplaySubject subject]] autoconnect];
+ signal.name = [NSString stringWithFormat:@"[%@] -replayLazily", self.name];
return signal;
}
@@ -1008,8 +1023,8 @@ - (RACSignal *)let:(RACSignal * (^)(RACSignal *sharedSignal))letBlock {
NSParameterAssert(letBlock != NULL);
return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
- RACConnectableSignal *connectable = [self publish];
- RACDisposable *finalDisposable = [letBlock(connectable) subscribeNext:^(id x) {
+ RACMulticastConnection *connection = [self publish];
+ RACDisposable *finalDisposable = [letBlock(connection.signal) subscribeNext:^(id x) {
[subscriber sendNext:x];
} error:^(NSError *error) {
[subscriber sendError:error];
@@ -1017,10 +1032,10 @@ - (RACSignal *)let:(RACSignal * (^)(RACSignal *sharedSignal))letBlock {
[subscriber sendCompleted];
}];
- RACDisposable *connectableDisposable = [connectable connect];
+ RACDisposable *connectionDisposable = [connection connect];
return [RACDisposable disposableWithBlock:^{
- [connectableDisposable dispose];
+ [connectionDisposable dispose];
[finalDisposable dispose];
}];
} name:@"[%@] -let:", self.name];
@@ -1142,18 +1157,6 @@ - (RACSignal *)retry {
return signal;
}
-- (RACCancelableSignal *)asCancelableToSubject:(RACSubject *)subject withBlock:(void (^)(void))block {
- return [RACCancelableSignal cancelableSignalSourceSignal:self subject:subject withBlock:block];
-}
-
-- (RACCancelableSignal *)asCancelableWithBlock:(void (^)(void))block {
- return [RACCancelableSignal cancelableSignalSourceSignal:self withBlock:block];
-}
-
-- (RACCancelableSignal *)asCancelable {
- return [self asCancelableWithBlock:NULL];
-}
-
- (RACSignal *)sample:(RACSignal *)sampler {
NSParameterAssert(sampler != nil);
View
1  ReactiveCocoaFramework/ReactiveCocoa/RACSignalSequence.m
@@ -7,7 +7,6 @@
//
#import "RACSignalSequence.h"
-#import "RACConnectableSignal.h"
#import "RACDisposable.h"
#import "RACReplaySubject.h"
#import "RACSignal+Operations.h"
View
3  ReactiveCocoaFramework/ReactiveCocoa/ReactiveCocoa.h
@@ -15,9 +15,8 @@
#import <ReactiveCocoa/NSSet+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSString+RACSequenceAdditions.h>
#import <ReactiveCocoa/RACBehaviorSubject.h>
-#import <ReactiveCocoa/RACCancelableSignal.h>
#import <ReactiveCocoa/RACCommand.h>
-#import <ReactiveCocoa/RACConnectableSignal.h>
+#import <ReactiveCocoa/RACMulticastConnection.h>
#import <ReactiveCocoa/RACDisposable.h>
#import <ReactiveCocoa/RACGroupedSignal.h>
#import <ReactiveCocoa/RACMaybe.h>
View
78 ReactiveCocoaFramework/ReactiveCocoaTests/RACConnectableSignalSpec.m
@@ -1,78 +0,0 @@
-//
-// RACConnectableSignalSpec.m
-// ReactiveCocoa
-//
-// Created by Josh Abernathy on 10/8/12.
-// Copyright (c) 2012 GitHub, Inc. All rights reserved.
-//
-
-#import "RACConnectableSignal.h"
-#import "RACDisposable.h"
-#import "RACSignal+Operations.h"
-#import "RACSubscriber.h"
-
-SpecBegin(RACConnectableSignal)
-
-describe(@"-autoconnect", ^{
- __block BOOL disposed = NO;
- __block NSUInteger numberOfSubscriptions = 0;
- __block RACSignal *signal;
-
- beforeEach(^{
- disposed = NO;
- numberOfSubscriptions = 0;
- signal = [[[RACConnectableSignal
- createSignal:^(id<RACSubscriber> subscriber) {
- numberOfSubscriptions++;
-
- return [RACDisposable disposableWithBlock:^{
- numberOfSubscriptions--;
- disposed = YES;
- }];
- }]
- publish]
- autoconnect];
- });
-
- it(@"should connect to the underlying signal on the first subscription", ^{
- [signal subscribeNext:^(id _) {}];
-
- expect(numberOfSubscriptions).to.equal(1);
- });
-
- it(@"shouldn't reconnect for more subscriptions", ^{
- [signal subscribeNext:^(id _) {}];
- [signal subscribeNext:^(id _) {}];
-
- expect(numberOfSubscriptions).to.equal(1);
- });
-
- it(@"should dispose when the last subscription disposes", ^{
- RACDisposable *disposable1 = [signal subscribeNext:^(id _) {}];
- RACDisposable *disposable2 = [signal subscribeNext:^(id _) {}];
-
- [disposable2 dispose];
- expect(disposed).to.beFalsy();
-
- [disposable1 dispose];
- expect(disposed).to.beTruthy();
- });
-
- it(@"should reconnect after all the original subscriptions have been disposed", ^{
- RACDisposable *disposable = [signal subscribeNext:^(id _) {}];
- expect(numberOfSubscriptions).to.equal(1);
-
- [disposable dispose];
- expect(disposed).to.beTruthy();
-
- expect(numberOfSubscriptions).to.equal(0);
-
- disposed = NO;
- disposable = [signal subscribeNext:^(id _) {}];
- expect(numberOfSubscriptions).to.equal(1);
- [disposable dispose];
- expect(disposed).to.beTruthy();
- });
-});
-
-SpecEnd
View
93 ReactiveCocoaFramework/ReactiveCocoaTests/RACMulticastConnectionSpec.m
@@ -0,0 +1,93 @@
+//
+// RACMulticastConnectionSpec.m
+// ReactiveCocoa
+//
+// Created by Josh Abernathy on 10/8/12.
+// Copyright (c) 2012 GitHub, Inc. All rights reserved.
+//
+
+#import "RACMulticastConnection.h"
+#import "RACDisposable.h"
+#import "RACSignal+Operations.h"
+#import "RACSubscriber.h"
+
+SpecBegin(RACMulticastConnection)
+
+__block NSUInteger subscriptionCount = 0;
+__block RACMulticastConnection *connection;
+__block BOOL disposed = NO;
+
+beforeEach(^{
+ subscriptionCount = 0;
+ disposed = NO;
+ connection = [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
+ subscriptionCount++;
+ return [RACDisposable disposableWithBlock:^{
+ disposed = YES;
+ }];
+ }] publish];
+ expect(subscriptionCount).to.equal(0);
+});
+
+describe(@"-connect", ^{
@jspahrsummers Owner

Can you also add a test that verifies the behavior of -connect (same disposable returned, no new subscription) after the original subscription is terminated?

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ it(@"should subscribe to the underlying signal", ^{
+ [connection connect];
+ expect(subscriptionCount).to.equal(1);
+ });
+
+ it(@"should return the same disposable for each invocation", ^{
+ RACDisposable *d1 = [connection connect];
+ RACDisposable *d2 = [connection connect];
+ expect(d1).to.equal(d2);
@jspahrsummers Owner

This test should also verify that subscriptionCount is still one.

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ expect(subscriptionCount).to.equal(1);
+ });
+
+ it(@"shouldn't reconnect after disposal", ^{
+ RACDisposable *disposable1 = [connection connect];
+ expect(subscriptionCount).to.equal(1);
+
+ [disposable1 dispose];
+
+ RACDisposable *disposable2 = [connection connect];
+ expect(subscriptionCount).to.equal(1);
+ expect(disposable1).to.equal(disposable2);
+ });
+});
+
+describe(@"-autoconnect", ^{
+ __block RACSignal *autoconnectedSignal;
+
+ beforeEach(^{
+ autoconnectedSignal = [connection autoconnect];
+ });
+
+ it(@"should subscribe to the multicasted signal on the first subscription", ^{
+ expect(subscriptionCount).to.equal(0);
+
+ [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+
+ [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+ });
+
+ it(@"should dispose of the multicasted subscription when the signal has no subscribers", ^{
@jspahrsummers Owner

It might be a bit redundant with this test, but I still think it'd be a good idea to verify that a new subscription doesn't automatically reconnect.

@joshaber Owner
joshaber added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
+
+ expect(disposed).to.beFalsy();
+ [disposable dispose];
+ expect(disposed).to.beTruthy();
+ });
+
+ it(@"shouldn't reconnect after disposal", ^{
+ RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+ [disposable dispose];
+
+ disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
+ expect(subscriptionCount).to.equal(1);
+ [disposable dispose];
+ });
+});
+
+SpecEnd
Something went wrong with that request. Please try again.