├── ReactiveCocoaFramework
├── ReactiveCocoa
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ ├── RACSwizzling.h
│ ├── RACEagerSequence.h
│ ├── RACEmptySequence.h
│ ├── RACUnarySequence.h
│ ├── RACImmediateScheduler.h
│ ├── RACValueTransformer.h
│ ├── RACSwizzling.m
│ ├── NSObject+RACDescription.m
│ ├── RACMulticastConnection+Private.h
│ ├── UIGestureRecognizer+RACSignalSupport.h
│ ├── NSObject+RACDeallocating.h
│ ├── RACSubscriptionScheduler.h
│ ├── RACUnit.h
│ ├── NSArray+RACSequenceAdditions.m
│ ├── NSString+RACSequenceAdditions.m
│ ├── UITextField+RACSignalSupport.h
│ ├── NSText+RACSignalSupport.h
│ ├── NSObject+RACDescription.h
│ ├── NSSet+RACSequenceAdditions.m
│ ├── ReactiveCocoa-Prefix.pch
│ ├── RACUnit.m
│ ├── RACGroupedSignal.h
│ ├── NSObject+RACObservablePropertySubject.h
│ ├── NSOrderedSet+RACSequenceAdditions.m
│ ├── RACSignalSequence.h
│ ├── UIControl+RACSignalSupport.h
│ ├── RACDelegateProxy.h
│ ├── RACGroupedSignal.m
│ ├── NSSet+RACSequenceAdditions.h
│ ├── NSArray+RACSequenceAdditions.h
│ ├── NSEnumerator+RACSequenceAdditions.h
│ ├── NSObject+RACObservablePropertySubject.m
│ ├── RACScopedDisposable.h
│ ├── NSEnumerator+RACSequenceAdditions.m
│ ├── RACObjCRuntime.h
│ ├── NSOrderedSet+RACSequenceAdditions.h
│ ├── RACArraySequence.h
│ ├── RACBehaviorSubject.h
│ ├── RACTupleSequence.h
│ ├── RACSignal+Private.h
│ ├── RACStringSequence.h
│ ├── NSString+RACSequenceAdditions.h
│ ├── NSControl+RACCommandSupport.h
│ ├── RACSubject.h
│ ├── UITextView+RACSignalSupport.h
│ ├── UITextField+RACSignalSupport.m
│ ├── NSObject+RACDeallocating.m
│ ├── UIBarButtonItem+RACCommandSupport.h
│ ├── NSControl+RACTextSignalSupport.h
│ ├── RACScopedDisposable.m
│ ├── NSString+RACKeyPathUtilities.h
│ ├── RACReplaySubject.h
│ ├── NSString+RACKeyPathUtilities.m
│ ├── RACDisposable.h
│ ├── RACDynamicSequence.h
│ ├── RACQueueScheduler.h
│ ├── RACPropertySubject.h
│ ├── RACValueTransformer.m
│ ├── NSDictionary+RACSequenceAdditions.m
│ ├── NSObject+RACKVOWrapperPrivate.h
│ ├── UIGestureRecognizer+RACSignalSupport.m
│ ├── RACBlockTrampoline.h
│ ├── RACBinding.h
│ ├── ReactiveCocoa-Info.plist
│ ├── RACBacktrace.h
│ ├── RACEventTrampoline.h
│ ├── RACImmediateScheduler.m
│ ├── NSText+RACSignalSupport.m
│ ├── UIControl+RACSignalSupport.m
│ ├── RACScheduler+Private.h
│ ├── NSControl+RACTextSignalSupport.m
│ ├── NSDictionary+RACSequenceAdditions.h
│ ├── RACObjCRuntime.m
│ ├── RACBinding+Private.h
│ ├── RACKVOTrampoline.h
│ ├── RACPropertySubject+Private.h
│ ├── RACSubscriptionScheduler.m
│ ├── UITextView+RACSignalSupport.m
│ ├── NSObject+RACSelectorSignal.h
│ ├── NSObject+RACAppKitBindings.h
│ ├── NSObject+RACKVOWrapper.h
│ ├── RACBehaviorSubject.m
│ ├── NSControl+RACCommandSupport.m
│ ├── RACBacktrace+Private.h
│ ├── RACSubscriptingAssignmentTrampoline.m
│ ├── RACSubject.m
│ ├── RACSubscriptingAssignmentTrampoline.h
│ ├── RACEmptySequence.m
│ ├── NSInvocation+RACTypeParsing.h
│ ├── RACDisposable.m
│ ├── NSObject+RACAppKitBindings.m
│ ├── RACEvent.h
│ ├── RACCompoundDisposable.h
│ ├── RACMulticastConnection.h
│ ├── RACStringSequence.m
│ ├── RACSignalSequence.m
│ ├── RACMulticastConnection.m
│ ├── RACEagerSequence.m
│ ├── UIBarButtonItem+RACCommandSupport.m
│ ├── NSObject+RACSelectorSignal.m
│ ├── RACTupleSequence.m
│ ├── RACUnarySequence.m
│ ├── RACSubscriber.h
│ ├── RACQueueScheduler.m
│ ├── RACSubscriber.m
│ ├── ReactiveCocoa.h
│ ├── RACBinding.m
│ ├── RACDelegateProxy.m
│ ├── RACObservablePropertySubject.h
│ ├── RACKVOTrampoline.m
│ ├── RACCompoundDisposable.m
│ ├── RACEvent.m
│ ├── RACPropertySubject.m
│ ├── NSObject+RACKVOWrapper.m
│ ├── RACReplaySubject.m
│ ├── RACArraySequence.m
│ └── RACEventTrampoline.m
├── ReactiveCocoaTests
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ ├── RACSubclassObject.m
│ ├── RACSubclassObject.h
│ ├── ReactiveCocoaTests-Prefix.pch
│ ├── RACSequenceExamples.h
│ ├── RACPropertySubjectExamples.h
│ ├── RACPropertySignalExamples.h
│ ├── NSObjectRACPropertySubscribingExamples.h
│ ├── NSEnumeratorRACSequenceAdditionsSpec.m
│ ├── ReactiveCocoaTests-Info.plist
│ ├── RACSubscriberExamples.h
│ ├── RACStreamExamples.h
│ ├── NSTextRACSupportSpec.m
│ ├── RACPropertySubjectSpec.m
│ ├── NSObjectRACDeallocatingSpec.m
│ ├── RACSubscriptingAssignmentTrampolineSpec.m
│ ├── NSStringRACKeyPathUtilitiesSpec.m
│ ├── RACBlockTrampolineSpec.m
│ ├── RACTestObject.m
│ ├── RACTestObject.h
│ ├── NSObjectRACSelectorSignal.m
│ ├── RACCompoundDisposableSpec.m
│ ├── RACEventSpec.m
│ ├── NSNotificationCenterRACSupportSpec.m
│ ├── RACBacktraceSpec.m
│ ├── RACSubscriberSpec.m
│ ├── RACPropertySignalExamples.m
│ └── RACMulticastConnectionSpec.m
└── ReactiveCocoa.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── xcshareddata
│ └── xcschemes
│ └── ReactiveCocoa-iOS.xcscheme
├── Documentation
├── README.md
└── DifferencesFromRx.md
├── script
├── targets.awk
├── bootstrap
├── xcodebuild.awk
├── README.md
├── LICENSE.md
└── cibuild
├── .gitignore
├── RACExtensions
├── NSFileHandle+RACSupport.h
├── NSNotificationCenter+RACSupport.h
├── NSData+RACSupport.h
├── NSString+RACSupport.h
├── NSNotificationCenter+RACSupport.m
├── NSData+RACSupport.m
├── NSString+RACSupport.m
├── NSFileHandle+RACSupport.m
└── NSTask+RACSupport.h
├── .gitmodules
├── CONTRIBUTING.md
└── LICENSE.md
/ReactiveCocoaFramework/ReactiveCocoa/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Documentation/README.md:
--------------------------------------------------------------------------------
1 | This folder contains conceptual documentation and design guidelines that don't
2 | fit well on a single class or in any specific header file.
3 |
--------------------------------------------------------------------------------
/script/targets.awk:
--------------------------------------------------------------------------------
1 | BEGIN {
2 | FS = "\n";
3 | }
4 |
5 | /Targets:/ {
6 | while (getline && $0 != "") {
7 | if ($0 ~ /Tests/) continue;
8 |
9 | sub(/^ +/, "");
10 | print "'" $0 "'";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | build/*
3 | *.pbxuser
4 | !default.pbxuser
5 | *.mode1v3
6 | !default.mode1v3
7 | *.mode2v3
8 | !default.mode2v3
9 | *.perspectivev3
10 | !default.perspectivev3
11 | *.xcworkspace
12 | !default.xcworkspace
13 | xcuserdata
14 | profile
15 | *.moved-aside
16 |
17 |
--------------------------------------------------------------------------------
/script/bootstrap:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SCRIPT_DIR=$(dirname "$0")
4 | cd "$SCRIPT_DIR/.."
5 |
6 | set -o errexit
7 |
8 | echo "*** Updating submodules..."
9 | git submodule sync --quiet
10 | git submodule update --init
11 | git submodule foreach --recursive --quiet "git submodule sync --quiet && git submodule update --init"
12 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSubclassObject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubclassObject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/18/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubclassObject.h"
10 |
11 | @implementation RACSubclassObject
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSubclassObject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubclassObject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/18/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACTestObject.h"
10 |
11 | @interface RACSubclassObject : RACTestObject
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSwizzling.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSwizzling.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/3/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | extern void RACSwizzle(Class class, SEL originalSelector, SEL newSelector);
13 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/ReactiveCocoaTests-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // ReactiveCocoaTests-Prefix.pch
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-29.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define EXP_SHORTHAND
12 | #import "Specta.h"
13 | #import "Expecta.h"
14 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEagerSequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACEagerSequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 02/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACArraySequence.h"
10 |
11 | // Private class that implements an eager sequence.
12 | @interface RACEagerSequence : RACArraySequence
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEmptySequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACEmptySequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class representing an empty sequence.
12 | @interface RACEmptySequence : RACSequence
13 | @end
14 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACUnarySequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACUnarySequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-01.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class representing a sequence of exactly one value.
12 | @interface RACUnarySequence : RACSequence
13 | @end
14 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACImmediateScheduler.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACImmediateScheduler.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // A scheduler which immediately executes its scheduled blocks.
12 | @interface RACImmediateScheduler : RACScheduler
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACValueTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACValueTransformer.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/6/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface RACValueTransformer : NSValueTransformer
13 |
14 | + (instancetype)transformerWithBlock:(id (^)(id value))block;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSwizzling.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSwizzling.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/3/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSwizzling.h"
10 | #import "JRSwizzle.h"
11 |
12 |
13 | void RACSwizzle(Class class, SEL originalSelector, SEL newSelector) {
14 | [class jr_swizzleMethod:originalSelector withMethod:newSelector error:NULL];
15 | }
16 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACDescription.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACDescription.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACDescription.h"
10 |
11 | @implementation NSObject (RACDescription)
12 |
13 | - (NSString *)rac_description {
14 | return [[NSString alloc] initWithFormat:@"<%@: %p>", self.class, self];
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACMulticastConnection+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSubject;
12 |
13 | @interface RACMulticastConnection ()
14 |
15 | - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIGestureRecognizer+RACSignalSupport.h
3 | // Talks
4 | //
5 | // Created by Josh Vera on 5/5/13.
6 | // Copyright (c) 2013 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface UIGestureRecognizer (RACSignalSupport)
14 |
15 | // Returns a signal that sends the receiver when its gesture occurs.
16 | - (RACSignal *)rac_gestureSignal;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACDeallocating.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACDeallocating.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Kazuo Koga on 2013/03/15.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface NSObject (RACDeallocating)
14 |
15 | // Returns a signal that will complete after the receiver has been deallocated.
16 | - (RACSignal *)rac_didDeallocSignal;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriptionScheduler.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriptionScheduler.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // A private scheduler used only for subscriptions. See the private
12 | // +[RACScheduler subscriptionScheduler] method for more information.
13 | @interface RACSubscriptionScheduler : RACScheduler
14 | @end
15 |
--------------------------------------------------------------------------------
/RACExtensions/NSFileHandle+RACSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSFileHandle+RACSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/10/12.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface NSFileHandle (RACSupport)
13 |
14 | // Read any available data in the background and send it. Completes when data
15 | // length is <= 0.
16 | - (RACSignal *)rac_readInBackground;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACUnit.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACUnit.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/27/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | // A unit represents an empty value.
13 | //
14 | // It should never be necessary to create a unit yourself. Just use +defaultUnit.
15 | @interface RACUnit : NSObject
16 |
17 | // A singleton instance.
18 | + (RACUnit *)defaultUnit;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSArray+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSArray+RACSequenceAdditions.h"
10 | #import "RACArraySequence.h"
11 |
12 | @implementation NSArray (RACSequenceAdditions)
13 |
14 | - (RACSequence *)rac_sequence {
15 | return [RACArraySequence sequenceWithArray:self offset:0];
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/specta"]
2 | path = external/specta
3 | url = git://github.com/github/specta.git
4 | [submodule "external/expecta"]
5 | path = external/expecta
6 | url = git://github.com/github/expecta.git
7 | [submodule "external/jrswizzle"]
8 | path= external/jrswizzle
9 | url = git://github.com/rentzsch/jrswizzle.git
10 | [submodule "ReactiveCocoaFramework/ReactiveCocoa/libextobjc"]
11 | path = ReactiveCocoaFramework/ReactiveCocoa/libextobjc
12 | url = git://github.com/jspahrsummers/libextobjc.git
13 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSString+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSString+RACSequenceAdditions.h"
10 | #import "RACStringSequence.h"
11 |
12 | @implementation NSString (RACSequenceAdditions)
13 |
14 | - (RACSequence *)rac_sequence {
15 | return [RACStringSequence sequenceWithString:self offset:0];
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UITextField+RACSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+RACSignalSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface UITextField (RACSignalSupport)
14 |
15 | // Creates and returns a signal for the text of the field. It always starts with
16 | // the current text.
17 | - (RACSignal *)rac_textSignal;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSText+RACSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSText+RACSignalSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-03-08.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface NSText (RACSignalSupport)
14 |
15 | // Returns a signal which sends the current `string` of the receiver, then the
16 | // new value any time it changes.
17 | - (RACSignal *)rac_textSignal;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSequenceExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSequenceExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-01.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for RACSequence instances.
10 | extern NSString * const RACSequenceExamples;
11 |
12 | // RACSequence *
13 | extern NSString * const RACSequenceExampleSequence;
14 |
15 | // NSArray *
16 | extern NSString * const RACSequenceExampleExpectedValues;
17 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACDescription.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACDescription.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSObject (RACDescription)
12 |
13 | // Returns a simplified description of the receiver, which does not invoke
14 | // -description (and thus should be much faster in many cases).
15 | - (NSString *)rac_description;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/RACExtensions/NSNotificationCenter+RACSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSNotificationCenter+RACSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/10/12.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface NSNotificationCenter (RACSupport)
13 |
14 | // Sends the NSNotification every time the notification is posted.
15 | - (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSSet+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSSet+RACSequenceAdditions.h"
10 | #import "NSArray+RACSequenceAdditions.h"
11 |
12 | @implementation NSSet (RACSequenceAdditions)
13 |
14 | - (RACSequence *)rac_sequence {
15 | // TODO: First class support for set sequences.
16 | return self.allObjects.rac_sequence;
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/ReactiveCocoa-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'ReactiveCocoa' target in the 'ReactiveCocoa' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #import "RACBacktrace+Private.h"
8 | #endif
9 |
10 | #undef NSAssert
11 | #undef NSParameterAssert
12 |
13 | extern void NSAssert(int condition, ...) __attribute__((unavailable("Use NSCAssert instead.")));
14 | extern void NSParameterAssert(int condition, ...) __attribute__((unavailable("Use NSCParameterAssert instead.")));
15 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACUnit.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACUnit.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/27/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACUnit.h"
10 |
11 |
12 | @implementation RACUnit
13 |
14 |
15 | #pragma mark API
16 |
17 | + (RACUnit *)defaultUnit {
18 | static dispatch_once_t onceToken;
19 | static RACUnit *defaultUnit = nil;
20 | dispatch_once(&onceToken, ^{
21 | defaultUnit = [[self alloc] init];
22 | });
23 |
24 | return defaultUnit;
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACGroupedSignal.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACGroupedSignal.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/2/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | // A grouped signal is used by -[RACSignal groupBy:transform:].
13 | @interface RACGroupedSignal : RACSubject
14 |
15 | // The key shared by the group.
16 | @property (nonatomic, readonly, copy) id key;
17 |
18 | + (instancetype)signalWithKey:(id)key;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACPropertySubjectExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySubjectExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 30/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for RACPropertySubject and it's subclasses.
10 | extern NSString * const RACPropertySubjectExamples;
11 |
12 | // A block of type `RACPropertySubject (^)(void)`, which should return a new
13 | // RACPropertySubject.
14 | extern NSString * const RACPropertySubjectExampleGetPropertyBlock;
15 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACObservablePropertySubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACObservablePropertySubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 01/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | @class RACObservablePropertySubject;
11 |
12 | @interface NSObject (RACObservablePropertySubject)
13 |
14 | // Returns a property subject interface to the receiver's key path.
15 | - (RACObservablePropertySubject *)rac_propertyForKeyPath:(NSString *)keyPath;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSOrderedSet+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSOrderedSet+RACSequenceAdditions.h"
10 | #import "NSArray+RACSequenceAdditions.h"
11 |
12 | @implementation NSOrderedSet (RACSequenceAdditions)
13 |
14 | - (RACSequence *)rac_sequence {
15 | // TODO: First class support for ordered set sequences.
16 | return self.array.rac_sequence;
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSignalSequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSignalSequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-09.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | // Private class that adapts a RACSignal to the RACSequence interface.
14 | @interface RACSignalSequence : RACSequence
15 |
16 | // Returns a sequence for enumerating over the given signal.
17 | + (RACSequence *)sequenceWithSignal:(RACSignal *)signal;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIControl+RACSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+RACSignalSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface UIControl (RACSignalSupport)
14 |
15 | // Creates and returns a signal that sends the sender of the control event
16 | // whenever one of the control events is triggered.
17 | - (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACDelegateProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACDelegateProxy.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/19/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACEventTrampoline;
12 |
13 | @interface RACDelegateProxy : NSObject
14 |
15 | @property (nonatomic, weak) id actualDelegate;
16 |
17 | + (instancetype)proxyWithProtocol:(Protocol *)protocol andDelegator:(NSObject *)delegator;
18 |
19 | - (void)addTrampoline:(RACEventTrampoline *)trampoline;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACGroupedSignal.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACGroupedSignal.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/2/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACGroupedSignal.h"
10 |
11 | @interface RACGroupedSignal ()
12 | @property (nonatomic, copy) id key;
13 | @end
14 |
15 | @implementation RACGroupedSignal
16 |
17 | #pragma mark API
18 |
19 | + (instancetype)signalWithKey:(id)key {
20 | RACGroupedSignal *subject = [self subject];
21 | subject.key = key;
22 | return subject;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSSet+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSSet (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence corresponding to the receiver.
16 | //
17 | // Mutating the receiver will not affect the sequence after it's been created.
18 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSArray+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSArray (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence corresponding to the receiver.
16 | //
17 | // Mutating the receiver will not affect the sequence after it's been created.
18 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSEnumerator+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 07/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSEnumerator (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence corresponding to the receiver.
16 | //
17 | // The receiver is exhausted lazily as the sequence is enumerated.
18 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACObservablePropertySubject.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACObservablePropertySubject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 01/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACObservablePropertySubject.h"
10 | #import "RACObservablePropertySubject.h"
11 |
12 | @implementation NSObject (RACObservablePropertySubject)
13 |
14 | - (RACObservablePropertySubject *)rac_propertyForKeyPath:(NSString *)keyPath {
15 | return [RACObservablePropertySubject propertyWithTarget:self keyPath:keyPath];
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACScopedDisposable.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACScopedDisposable.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/28/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | // A disposable that calls its own -dispose when it is dealloc'd.
13 | @interface RACScopedDisposable : RACDisposable
14 |
15 | // Creates a new scoped disposable that will also dispose of the given
16 | // disposable when it is dealloc'd.
17 | + (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSEnumerator+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 07/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSEnumerator+RACSequenceAdditions.h"
10 | #import "RACSequence.h"
11 | #import "EXTScope.h"
12 |
13 | @implementation NSEnumerator (RACSequenceAdditions)
14 |
15 | - (RACSequence *)rac_sequence {
16 | return [RACSequence sequenceWithHeadBlock:^{
17 | return [self nextObject];
18 | } tailBlock:^{
19 | return self.rac_sequence;
20 | }];
21 | }
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACObjCRuntime.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACObjCRuntime.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/19/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface RACObjCRuntime : NSObject
13 |
14 | + (void)findMethod:(SEL)method inProtocol:(Protocol *)protocol outMethod:(struct objc_method_description *)outMethod;
15 | + (const char *)getMethodTypesForMethod:(SEL)method inProtocol:(Protocol *)protocol;
16 | + (BOOL)method:(SEL)method existsInProtocol:(Protocol *)protocol;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSOrderedSet+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSOrderedSet (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence corresponding to the receiver.
16 | //
17 | // Mutating the receiver will not affect the sequence after it's been created.
18 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/RACExtensions/NSData+RACSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+RACSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface NSData (RACSupport)
13 |
14 | // Read the data at the URL using -[NSData initWithContentsOfURL:options:error:].
15 | // Sends the data or the error.
16 | //
17 | // scheduler - cannot be nil.
18 | + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACArraySequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACArraySequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class that adapts an array to the RACSequence interface.
12 | @interface RACArraySequence : RACSequence
13 |
14 | // Returns a sequence for enumerating over the given array, starting from the
15 | // given offset. The array will be copied to prevent mutation.
16 | + (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBehaviorSubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBehaviorSubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/16/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | // A behavior subject sends the last value it received when it is subscribed to.
13 | @interface RACBehaviorSubject : RACSubject
14 |
15 | // Creates a new behavior subject with a default value. If it hasn't received
16 | // any values when it gets subscribed to, it sends the default value.
17 | + (instancetype)behaviorSubjectWithDefaultValue:(id)value;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACTupleSequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACTupleSequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-01.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class that adapts a RACTuple to the RACSequence interface.
12 | @interface RACTupleSequence : RACSequence
13 |
14 | // Returns a sequence for enumerating over the given backing array (from
15 | // a RACTuple), starting from the given offset.
16 | + (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSignal+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSignal+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/15/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACDisposable;
12 |
13 | @interface RACSignal ()
14 |
15 | @property (nonatomic, copy) RACDisposable * (^didSubscribe)(id subscriber);
16 |
17 | // All access to this must be synchronized.
18 | @property (nonatomic, strong) NSMutableArray *subscribers;
19 |
20 | - (void)performBlockOnEachSubscriber:(void (^)(id subscriber))block;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACStringSequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACStringSequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class that adapts a string to the RACSequence interface.
12 | @interface RACStringSequence : RACSequence
13 |
14 | // Returns a sequence for enumerating over the given string, starting from the
15 | // given character offset. The string will be copied to prevent mutation.
16 | + (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/script/xcodebuild.awk:
--------------------------------------------------------------------------------
1 | # Exit statuses:
2 | #
3 | # 0 - No errors found.
4 | # 1 - Build or test failure. Errors will be logged automatically.
5 | # 2 - Untestable target. Retry with the "build" action.
6 |
7 | BEGIN {
8 | status = 0;
9 | }
10 |
11 | {
12 | print;
13 | fflush(stdout);
14 | }
15 |
16 | /is not valid for Testing/ {
17 | exit 2;
18 | }
19 |
20 | /[0-9]+: (error|warning):/ {
21 | errors = errors $0 "\n";
22 | }
23 |
24 | /(TEST|BUILD) FAILED/ {
25 | status = 1;
26 | }
27 |
28 | END {
29 | if (length(errors) > 0) {
30 | print "\n*** All errors:\n" errors;
31 | }
32 |
33 | fflush(stdout);
34 | exit status;
35 | }
36 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSString+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSString (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence containing strings corresponding to each
16 | // composed character sequence in the receiver.
17 | //
18 | // Mutating the receiver will not affect the sequence after it's been created.
19 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACPropertySignalExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySignalExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 9/28/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for a signal-driven property.
10 | extern NSString * const RACPropertySignalExamples;
11 |
12 | // The block should have the signature:
13 | // void (^)(RACTestObject *testObject, NSString *keyPath, RACSignal *signal)
14 | // and should tie the value of the key path on testObject to signal. The value
15 | // for this key should not be nil.
16 | extern NSString * const RACPropertySignalExamplesSetupBlock;
17 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSControl+RACCommandSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSControl+RACCommandSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/3/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACCommand;
12 |
13 | @interface NSControl (RACCommandSupport)
14 |
15 | // Sets the control's command. When the control is clicked, the command is
16 | // executed with the sender of the event. The control's enabledness is bound
17 | // to the command's `canExecute`.
18 | //
19 | // Note: this will reset the control's target and action.
20 | @property (nonatomic, strong) RACCommand *rac_command;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/9/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | // A subject can be thought of as a signal that you can manually control by
13 | // sending next, completed, and error.
14 | //
15 | // They're most helpful in bridging the non-RAC world to RAC, since they let you
16 | // manually control the sending of events.
17 | @interface RACSubject : RACSignal
18 |
19 | // Returns a new subject.
20 | + (instancetype)subject;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UITextView+RACSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITextView+RACSignalSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/18/12.
6 | // Copyright (c) 2012 Cody Krieger. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface UITextView (RACSignalSupport)
14 |
15 | // Creates and returns a signal that sends the sender of the delegate method
16 | // whenever it is triggered.
17 | - (RACSignal *)rac_signalForDelegateMethod:(SEL)method;
18 |
19 | // Creates and returns a signal for the text of the field. It always starts with
20 | // the current text.
21 | - (RACSignal *)rac_textSignal;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UITextField+RACSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+RACSignalSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "UITextField+RACSignalSupport.h"
10 | #import "RACSignal.h"
11 | #import "UIControl+RACSignalSupport.h"
12 |
13 | @implementation UITextField (RACSignalSupport)
14 |
15 | - (RACSignal *)rac_textSignal {
16 | return [[[[self rac_signalForControlEvents:UIControlEventEditingChanged]
17 | map:^(UITextField *x) {
18 | return x.text;
19 | }]
20 | startWith:self.text]
21 | setNameWithFormat:@"%@ -rac_textSignal", self];
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACDeallocating.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACDeallocating.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Kazuo Koga on 2013/03/15.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACDeallocating.h"
10 | #import "NSObject+RACPropertySubscribing.h"
11 | #import "RACDisposable.h"
12 | #import "RACSubject.h"
13 |
14 | @implementation NSObject (RACDeallocating)
15 |
16 | - (RACSignal *)rac_didDeallocSignal {
17 | RACSubject *subject = [RACSubject subject];
18 |
19 | [self rac_addDeallocDisposable:[RACDisposable disposableWithBlock:^{
20 | [subject sendCompleted];
21 | }]];
22 |
23 | return subject;
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/RACExtensions/NSString+RACSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface NSString (RACSupport)
13 |
14 | // Reads in the contents of the file using +[NSString stringWithContentsOfURL:usedEncoding:error:].
15 | // Note that encoding won't be valid until the signal completes successfully.
16 | //
17 | // scheduler - cannot be nil.
18 | + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarButtonItem+RACCommandSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Kyle LeNeau on 3/27/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACCommand;
12 |
13 | @interface UIBarButtonItem (RACCommandSupport)
14 |
15 | // Sets the control's command. When the control is clicked, the command is
16 | // executed with the sender of the event. The control's enabledness is bound
17 | // to the command's `canExecute`.
18 | //
19 | // Note: this will reset the control's target and action.
20 | @property (nonatomic, strong) RACCommand *rac_command;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSControl+RACTextSignalSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSControl+RACTextSignalSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-03-08.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface NSControl (RACTextSignalSupport)
14 |
15 | // Observes a text-based control for changes.
16 | //
17 | // Using this method on a control without editable text is considered undefined
18 | // behavior.
19 | //
20 | // Returns a signal which sends the current string value of the receiver, then
21 | // the new value any time it changes.
22 | - (RACSignal *)rac_textSignal;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSObjectRACPropertySubscribingExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObjectRACPropertySubscribingExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Vera on 4/10/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for a signal-driven observation.
10 | extern NSString * const RACPropertySubscribingExamples;
11 |
12 | // The block should have the signature:
13 | // RACSignal * (^)(RACTestObject *testObject, NSString *keyPath, id observer)
14 | // and should observe the value of the key path on testObject with observer. The value
15 | // for this key should not be nil.
16 | extern NSString * const RACPropertySubscribingExamplesSetupBlock;
17 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSEnumeratorRACSequenceAdditionsSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSEnumeratorRACSequenceAdditionsSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 07/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSequenceExamples.h"
10 |
11 | #import "NSEnumerator+RACSequenceAdditions.h"
12 |
13 | SpecBegin(NSEnumeratorRACSequenceAdditions)
14 |
15 | describe(@"-rac_sequence", ^{
16 | NSArray *values = @[ @0, @1, @2, @3, @4 ];
17 | itShouldBehaveLike(RACSequenceExamples, ^{
18 | return @{
19 | RACSequenceExampleSequence: values.objectEnumerator.rac_sequence,
20 | RACSequenceExampleExpectedValues: values
21 | };
22 | });
23 | });
24 |
25 | SpecEnd
26 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACScopedDisposable.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACScopedDisposable.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/28/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACScopedDisposable.h"
10 |
11 | @implementation RACScopedDisposable
12 |
13 | #pragma mark Lifecycle
14 |
15 | + (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable {
16 | return [self disposableWithBlock:^{
17 | [disposable dispose];
18 | }];
19 | }
20 |
21 | - (void)dealloc {
22 | [self dispose];
23 | }
24 |
25 | #pragma mark RACDisposable
26 |
27 | - (RACScopedDisposable *)asScopedDisposable {
28 | // totally already are
29 | return self;
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/script/README.md:
--------------------------------------------------------------------------------
1 | These scripts are primarily meant to support the use of
2 | [Janky](https://github.com/github/janky). To use them, read the contents of this
3 | repository into a `script` folder:
4 |
5 | ```
6 | $ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git
7 | $ git fetch objc-build-scripts
8 | $ git read-tree --prefix=script/ -u objc-build-scripts/master
9 | ```
10 |
11 | Then commit the changes to incorporate the scripts into your own repository's
12 | history. You can also freely tweak the scripts for your specific project's
13 | needs.
14 |
15 | To bring in upstream changes later:
16 |
17 | ```
18 | $ git fetch -p objc-build-scripts
19 | $ git merge -Xsubtree=script objc-build-scripts/master
20 | ```
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSString+RACKeyPathUtilities.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACKeyPathUtilities.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 05/05/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSString (RACKeyPathUtilities)
12 |
13 | // Returns an array of the components of the receiver, or nil if the receiver is
14 | // not a valid key path.
15 | - (NSArray *)rac_keyPathComponents;
16 |
17 | // Returns a key path with all the components of the receiver except for the
18 | // last one or nil if the receiver is not a valid key path, or has only one
19 | // component.
20 | - (NSString *)rac_keyPathByDeletingLastKeyPathComponent;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACReplaySubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACReplaySubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/14/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | extern const NSUInteger RACReplaySubjectUnlimitedCapacity;
12 |
13 |
14 | // A replay subject saves the values it is sent (up to its defined capacity)
15 | // and resends those to new subscribers. It will also replay an error or
16 | // completion.
17 | @interface RACReplaySubject : RACSubject
18 |
19 | // Creates a new replay subject with the given capacity. A capacity of
20 | // RACReplaySubjectUnlimitedCapacity means values are never trimmed.
21 | + (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSString+RACKeyPathUtilities.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACKeyPathUtilities.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 05/05/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSString+RACKeyPathUtilities.h"
10 |
11 | @implementation NSString (RACKeyPathUtilities)
12 |
13 | - (NSArray *)rac_keyPathComponents {
14 | if (self.length == 0) {
15 | return nil;
16 | }
17 | return [self componentsSeparatedByString:@"."];
18 | }
19 |
20 | - (NSString *)rac_keyPathByDeletingLastKeyPathComponent {
21 | NSUInteger lastDotIndex = [self rangeOfString:@"." options:NSBackwardsSearch].location;
22 | if (lastDotIndex == NSNotFound) {
23 | return nil;
24 | }
25 | return [self substringToIndex:lastDotIndex];
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACDisposable.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACDisposable.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/16/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACScopedDisposable;
12 |
13 |
14 | // A disposable encapsulates the work necessary to tear down and cleanup a
15 | // subscription.
16 | @interface RACDisposable : NSObject
17 |
18 | + (instancetype)disposableWithBlock:(void (^)(void))block;
19 |
20 | // Performs the disposal work. Can be called multiple times, though sebsequent
21 | // calls won't do anything.
22 | - (void)dispose;
23 |
24 | // Returns a new disposable which will dispose of this disposable when it gets
25 | // dealloc'd.
26 | - (RACScopedDisposable *)asScopedDisposable;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/ReactiveCocoaTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.github.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACDynamicSequence.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACDynamicSequence.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Private class that implements a sequence dynamically using blocks.
12 | @interface RACDynamicSequence : RACSequence
13 |
14 | // Returns a sequence which evaluates `dependencyBlock` only once, the first
15 | // time either `headBlock` or `tailBlock` is evaluated. The result of
16 | // `dependencyBlock` will be passed into `headBlock` and `tailBlock` when
17 | // invoked.
18 | + (RACSequence *)sequenceWithLazyDependency:(id (^)(void))dependencyBlock headBlock:(id (^)(id dependency))headBlock tailBlock:(RACSequence *(^)(id dependency))tailBlock;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACQueueScheduler.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACQueueScheduler.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // A scheduler which asynchronously enqueues all its work to a private Grand
12 | // Central Dispatch queue.
13 | @interface RACQueueScheduler : RACScheduler
14 |
15 | // Initializes the receiver with the name of the scheduler and the queue which
16 | // the scheduler should target.
17 | //
18 | // name - The name of the scheduler.
19 | // targetQueue - The queue which the scheduler should target. Cannot be NULL.
20 | //
21 | // Returns the initialized object.
22 | - (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACPropertySubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 16/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubject.h"
10 |
11 | @class RACDisposable, RACBinding;
12 |
13 | // A RACPropertySubject saves the last value sent to it and resends it to new
14 | // subscribers. It will also resend error or completion.
15 | //
16 | // Values sent to a RACPropertySubject are also sent to it's bindings'
17 | // subscribers. Values sent to a RACProperty's bindings are also sent to the
18 | // RACPropertySubject.
19 | @interface RACPropertySubject : RACSubject
20 |
21 | // Returns a new RACPropertySubject with a starting value of `nil`.
22 | + (instancetype)property;
23 |
24 | // Returns a new binding of the RACPropertySubject.
25 | - (RACBinding *)binding;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSubscriberExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriberExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-27.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for implementors of .
10 | extern NSString * const RACSubscriberExamples;
11 |
12 | // id
13 | extern NSString * const RACSubscriberExampleSubscriber;
14 |
15 | // A block which returns an NSArray of the values received so far.
16 | extern NSString * const RACSubscriberExampleValuesReceivedBlock;
17 |
18 | // A block which returns any NSError received so far.
19 | extern NSString * const RACSubscriberExampleErrorReceivedBlock;
20 |
21 | // A block which returns a BOOL indicating whether the subscriber is successful
22 | // so far.
23 | extern NSString * const RACSubscriberExampleSuccessBlock;
24 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACStreamExamples.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACStreamExamples.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-01.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | // The name of the shared examples for a RACStream subclass.
10 | extern NSString * const RACStreamExamples;
11 |
12 | // The RACStream subclass to test.
13 | extern NSString * const RACStreamExamplesClass;
14 |
15 | // An infinite RACStream to test, making sure that certain operations
16 | // terminate.
17 | //
18 | // The stream should contain infinite RACUnit values.
19 | extern NSString * const RACStreamExamplesInfiniteStream;
20 |
21 | // A block with the signature:
22 | //
23 | // void (^)(RACStream *stream, NSArray *expectedValues)
24 | //
25 | // … used to verify that a stream contains the expected values.
26 | extern NSString * const RACStreamExamplesVerifyValuesBlock;
27 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | We love that you're interested in contributing to this project!
2 |
3 | To make the process as painless as possible, we have just a couple of guidelines
4 | that should make life easier for everyone involved.
5 |
6 | ## Prefer Pull Requests
7 |
8 | If you know exactly how to implement the feature being suggested or fix the bug
9 | being reported, please open a pull request instead of an issue. Pull requests are easier than
10 | patches or inline code blocks for discussing and merging the changes.
11 |
12 | If you can't make the change yourself, please open an issue after making sure
13 | that one isn't already logged.
14 |
15 | ## Contributing Code
16 |
17 | Fork this repository, make it awesomer (preferably in a branch named for the
18 | topic), send a pull request!
19 |
20 | All code contributions should match our [coding
21 | conventions](https://github.com/github/objective-c-conventions).
22 |
23 | Thanks for contributing! :boom::camel:
24 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSTextRACSupportSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSTextRACSupportSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-03-08.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSText+RACSignalSupport.h"
10 | #import "RACSignal.h"
11 |
12 | SpecBegin(NSTextRACSupport)
13 |
14 | it(@"NSTextView should send changes on rac_textSignal", ^{
15 | NSTextView *textView = [[NSTextView alloc] initWithFrame:NSZeroRect];
16 | expect(textView).notTo.beNil();
17 |
18 | NSMutableArray *strings = [NSMutableArray array];
19 | [textView.rac_textSignal subscribeNext:^(NSString *str) {
20 | [strings addObject:str];
21 | }];
22 |
23 | expect(strings).to.equal(@[ @"" ]);
24 |
25 | [textView insertText:@"f"];
26 | [textView insertText:@"o"];
27 | [textView insertText:@"b"];
28 |
29 | NSArray *expected = @[ @"", @"f", @"fo", @"fob" ];
30 | expect(strings).to.equal(expected);
31 | });
32 |
33 | SpecEnd
34 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACPropertySubjectSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySubjectSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 30/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACPropertySubject.h"
10 | #import "RACPropertySubjectExamples.h"
11 | #import "RACBinding.h"
12 | #import "RACDisposable.h"
13 | #import "NSObject+RACPropertySubscribing.h"
14 |
15 | SpecBegin(RACPropertySubject)
16 |
17 | describe(@"RACPropertySubject", ^{
18 | itShouldBehaveLike(RACPropertySubjectExamples, ^{
19 | return @{
20 | RACPropertySubjectExampleGetPropertyBlock: [^{ return [RACPropertySubject property]; } copy]
21 | };
22 | });
23 |
24 | describe(@"created with +subject", ^{
25 | itShouldBehaveLike(RACPropertySubjectExamples, ^{
26 | return @{
27 | RACPropertySubjectExampleGetPropertyBlock: [^{ return [RACPropertySubject subject]; } copy]
28 | };
29 | });
30 | });
31 | });
32 |
33 | SpecEnd
34 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACValueTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACValueTransformer.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/6/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACValueTransformer.h"
10 |
11 | @interface RACValueTransformer ()
12 | @property (nonatomic, copy) id (^transformBlock)(id value);
13 | @end
14 |
15 |
16 | @implementation RACValueTransformer
17 |
18 |
19 | #pragma mark NSValueTransformer
20 |
21 | + (BOOL)allowsReverseTransformation {
22 | return NO;
23 | }
24 |
25 | - (id)transformedValue:(id)value {
26 | return self.transformBlock(value);
27 | }
28 |
29 |
30 | #pragma mark API
31 |
32 | @synthesize transformBlock;
33 |
34 | + (instancetype)transformerWithBlock:(id (^)(id value))block {
35 | NSCParameterAssert(block != NULL);
36 |
37 | RACValueTransformer *transformer = [[self alloc] init];
38 | transformer.transformBlock = block;
39 | return transformer;
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/RACExtensions/NSNotificationCenter+RACSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNotificationCenter+RACSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/10/12.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSNotificationCenter+RACSupport.h"
10 | #import
11 |
12 | @implementation NSNotificationCenter (RACSupport)
13 |
14 | - (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
15 | @unsafeify(object);
16 | return [[RACSignal createSignal:^(id subscriber) {
17 | @strongify(object);
18 | id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
19 | [subscriber sendNext:note];
20 | }];
21 |
22 | return [RACDisposable disposableWithBlock:^{
23 | [self removeObserver:observer];
24 | }];
25 | }] setNameWithFormat:@"-rac_addObserverForName: %@ object: <%@: %p>", notificationName, [object class], object];
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSDictionary+RACSequenceAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+RACSequenceAdditions.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSDictionary+RACSequenceAdditions.h"
10 | #import "NSArray+RACSequenceAdditions.h"
11 | #import "RACSequence.h"
12 | #import "RACTuple.h"
13 |
14 | @implementation NSDictionary (RACSequenceAdditions)
15 |
16 | - (RACSequence *)rac_sequence {
17 | NSDictionary *immutableDict = [self copy];
18 |
19 | // TODO: First class support for dictionary sequences.
20 | return [immutableDict.allKeys.rac_sequence map:^(id key) {
21 | id value = immutableDict[key];
22 | return [RACTuple tupleWithObjects:key, value, nil];
23 | }];
24 | }
25 |
26 | - (RACSequence *)rac_keySequence {
27 | return self.allKeys.rac_sequence;
28 | }
29 |
30 | - (RACSequence *)rac_valueSequence {
31 | return self.allValues.rac_sequence;
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACKVOWrapperPrivate.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACKVOWrapperPrivate.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 1/15/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSObject (RACKVOWrapperPrivate)
12 |
13 | // Should only be manipulated while synchronized on the receiver.
14 | @property (nonatomic, strong) NSMutableArray *RACKVOTrampolines;
15 |
16 | // Remove the trampoline from the receiver.
17 | //
18 | // trampoline - The trampoline to add. Cannot be nil.
19 | //
20 | // This method is thread-safe.
21 | - (void)rac_addKVOTrampoline:(RACKVOTrampoline *)trampoline;
22 |
23 | // Removes the trampoline from the receiver. This does *not* stop the
24 | // trampoline's observation.
25 | //
26 | // trampoline - The trampoline to remove. Can be nil.
27 | //
28 | // This method is thread-safe.
29 | - (void)rac_removeKVOTrampoline:(RACKVOTrampoline *)trampoline;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/RACExtensions/NSData+RACSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+RACSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSData+RACSupport.h"
10 |
11 | @implementation NSData (RACSupport)
12 |
13 | + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler {
14 | NSCParameterAssert(scheduler != nil);
15 |
16 | RACReplaySubject *subject = [RACReplaySubject subject];
17 | [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ options: %lu scheduler: %@", URL, (unsigned long)options, scheduler];
18 |
19 | [scheduler schedule:^{
20 | NSError *error = nil;
21 | NSData *data = [[NSData alloc] initWithContentsOfURL:URL options:options error:&error];
22 | if(data == nil) {
23 | [subject sendError:error];
24 | } else {
25 | [subject sendNext:data];
26 | [subject sendCompleted];
27 | }
28 | }];
29 |
30 | return subject;
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/RACExtensions/NSString+RACSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+RACSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSString+RACSupport.h"
10 |
11 | @implementation NSString (RACSupport)
12 |
13 | + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler {
14 | NSCParameterAssert(scheduler != nil);
15 |
16 | RACReplaySubject *subject = [RACReplaySubject subject];
17 | [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ usedEncoding:scheduler: %@", URL, scheduler];
18 |
19 | [scheduler schedule:^{
20 | NSError *error = nil;
21 | NSString *string = [NSString stringWithContentsOfURL:URL usedEncoding:encoding error:&error];
22 | if(string == nil) {
23 | [subject sendError:error];
24 | } else {
25 | [subject sendNext:string];
26 | [subject sendCompleted];
27 | }
28 | }];
29 |
30 | return subject;
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIGestureRecognizer+RACSignalSupport.m
3 | // Talks
4 | //
5 | // Created by Josh Vera on 5/5/13.
6 | // Copyright (c) 2013 GitHub. All rights reserved.
7 | //
8 |
9 | #import "UIGestureRecognizer+RACSignalSupport.h"
10 | #import "RACEventTrampoline.h"
11 | #import
12 |
13 | @implementation UIGestureRecognizer (RACSignalSupport)
14 |
15 | - (RACSignal *)rac_gestureSignal {
16 | RACEventTrampoline *trampoline = [RACEventTrampoline trampolineForGestureRecognizer:self];
17 | [trampoline.subject setNameWithFormat:@"%@ -rac_gestureSignal", self];
18 |
19 | NSMutableSet *controlEventTrampolines = objc_getAssociatedObject(self, RACEventTrampolinesKey);
20 | if (controlEventTrampolines == nil) {
21 | controlEventTrampolines = [NSMutableSet set];
22 | objc_setAssociatedObject(self, RACEventTrampolinesKey, controlEventTrampolines, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
23 | }
24 |
25 | [controlEventTrampolines addObject:trampoline];
26 |
27 | return trampoline.subject;
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBlockTrampoline.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBlockTrampoline.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 10/21/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACTuple;
12 |
13 | // Allows a limited type of dynamic block invocation.
14 | @interface RACBlockTrampoline : NSObject
15 |
16 | // Invokes the given block with the given arguments. All of the block's
17 | // argument types must be objects and it must be typed to return an object.
18 | //
19 | // At this time, it only supports blocks that take up to 15 arguments. Any more
20 | // is just cray.
21 | //
22 | // block - The block to invoke. Must accept as many arguments as are given in
23 | // the arguments array. Cannot be nil.
24 | // arguments - The arguments with which to invoke the block. `RACTupleNil`s will
25 | // be passed as nils.
26 | //
27 | // Returns the return value of invoking the block.
28 | + (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBinding.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBinding.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 01/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSignal.h"
10 | #import "RACSubscriber.h"
11 |
12 | @class RACDisposable;
13 |
14 | // A binding of a RACPropertySubject.
15 | //
16 | // Values sent to the binding are sent to the binding's RACPropertySubject's
17 | // subscribers and subscribers of other RACBindings of the same property
18 | // subject, but are not sent to the receiver's subscribers. A binding's
19 | // subscribers will also receive values sent to the binding's property subject.
20 | @interface RACBinding : RACSignal
21 |
22 | // Binds the receiver to `binding` by subscribing each one to the other's
23 | // changes.
24 | //
25 | // When called, `binding`s current value will be sent to the receiver and the
26 | // receiver's current value will be discarded.
27 | //
28 | // Returns a disposable that can be used to stop the binding.
29 | - (RACDisposable *)bindTo:(RACBinding *)binding;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/ReactiveCocoa-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | com.github.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | FMWK
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSHumanReadableCopyright
26 | Copyright © 2012 GitHub, Inc. All rights reserved.
27 | NSPrincipalClass
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/script/LICENSE.md:
--------------------------------------------------------------------------------
1 | **Copyright (c) 2013 Justin Spahr-Summers**
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBacktrace.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBacktrace.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-08-20.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #ifdef DEBUG
10 |
11 | // Preserves backtraces across asynchronous calls.
12 | @interface RACBacktrace : NSObject
13 |
14 | // The backtrace from any previous thread.
15 | @property (nonatomic, strong, readonly) RACBacktrace *previousThreadBacktrace;
16 |
17 | // The call stack of this backtrace's thread.
18 | @property (nonatomic, copy, readonly) NSArray *callStackSymbols;
19 |
20 | // Captures the current thread's backtrace, appending it to any backtrace from
21 | // a previous thread.
22 | + (instancetype)captureBacktrace;
23 |
24 | // Same as +captureBacktrace, but omits the specified number of frames at the
25 | // top of the stack (in addition to this method itself).
26 | + (instancetype)captureBacktraceIgnoringFrames:(NSUInteger)ignoreCount;
27 |
28 | // Prints the backtrace of the current thread, appended to that of any previous
29 | // threads.
30 | + (void)printBacktrace;
31 |
32 | @end
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEventTrampoline.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACEventTrampoline.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/18/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | extern const char *RACEventTrampolinesKey;
13 |
14 | @class RACDelegateProxy;
15 |
16 | @interface RACEventTrampoline : NSObject {
17 | SEL delegateMethod;
18 | RACDelegateProxy *proxy;
19 | }
20 |
21 | + (instancetype)trampolineForControl:(UIControl *)control controlEvents:(UIControlEvents)controlEvents;
22 | + (instancetype)trampolineForTextView:(UITextView *)textView delegateMethod:(SEL)method;
23 |
24 | // Returns an event trampoline for the given gesture.
25 | + (instancetype)trampolineForGestureRecognizer:(UIGestureRecognizer *)gesture;
26 |
27 | - (void)didGetControlEvent:(id)sender;
28 | - (void)didGetDelegateEvent:(SEL)delegateMethod sender:(id)sender;
29 |
30 | @property (nonatomic, strong) RACSubject *subject;
31 | @property (nonatomic, strong) RACDelegateProxy *proxy;
32 | @property (nonatomic) SEL delegateMethod;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | **Copyright (c) 2012 - 2013, GitHub, Inc.**
2 | **All rights reserved.**
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | this software and associated documentation files (the "Software"), to deal in
6 | the Software without restriction, including without limitation the rights to
7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | the Software, and to permit persons to whom the Software is furnished to do so,
9 | subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACImmediateScheduler.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACImmediateScheduler.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACImmediateScheduler.h"
10 | #import "EXTScope.h"
11 | #import "RACScheduler+Private.h"
12 |
13 | @implementation RACImmediateScheduler
14 |
15 | #pragma mark Lifecycle
16 |
17 | - (id)init {
18 | return [super initWithName:@"com.ReactiveCocoa.RACScheduler.immediateScheduler"];
19 | }
20 |
21 | #pragma mark RACScheduler
22 |
23 | - (RACDisposable *)schedule:(void (^)(void))block {
24 | NSCParameterAssert(block != NULL);
25 |
26 | block();
27 | return nil;
28 | }
29 |
30 | - (RACDisposable *)after:(dispatch_time_t)when schedule:(void (^)(void))block {
31 | NSCParameterAssert(block != NULL);
32 |
33 | // Use a temporary semaphore to block the current thread until a specific
34 | // dispatch_time_t.
35 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
36 | dispatch_semaphore_wait(semaphore, when);
37 | dispatch_release(semaphore);
38 |
39 | block();
40 | return nil;
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSText+RACSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSText+RACSignalSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-03-08.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSText+RACSignalSupport.h"
10 | #import "EXTScope.h"
11 | #import "RACDisposable.h"
12 | #import "RACSignal.h"
13 | #import "RACSubscriber.h"
14 |
15 | @implementation NSText (RACSignalSupport)
16 |
17 | - (RACSignal *)rac_textSignal {
18 | @unsafeify(self);
19 | return [[[[RACSignal
20 | createSignal:^(id subscriber) {
21 | @strongify(self);
22 | id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) {
23 | [subscriber sendNext:note.object];
24 | }];
25 |
26 | return [RACDisposable disposableWithBlock:^{
27 | [NSNotificationCenter.defaultCenter removeObserver:observer];
28 | }];
29 | }]
30 | map:^(NSText *text) {
31 | return [text.string copy];
32 | }]
33 | startWith:[self.string copy]]
34 | setNameWithFormat:@"%@ -rac_textSignal", self];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/script/cibuild:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")/../ReactiveCocoaFramework"
4 | SCRIPT_DIR=../script
5 |
6 | ##
7 | ## Configuration Variables
8 | ##
9 |
10 | # The build configuration to use.
11 | if [ -z "$XCCONFIGURATION" ]
12 | then
13 | XCCONFIGURATION="Release"
14 | fi
15 |
16 | # A bootstrap script to run before building.
17 | #
18 | # If this file does not exist, it is not considered an error.
19 | BOOTSTRAP="$SCRIPT_DIR/bootstrap"
20 |
21 | # Extra build settings to pass to xcodebuild.
22 | XCODEBUILD_SETTINGS=
23 |
24 | ##
25 | ## Build Process
26 | ##
27 |
28 | if [ -f "$BOOTSTRAP" ]
29 | then
30 | echo "*** Bootstrapping..."
31 | bash "$BOOTSTRAP" || exit $?
32 | fi
33 |
34 | echo "*** Cleaning all targets..."
35 | xcodebuild -alltargets clean OBJROOT="$PWD/build" SYMROOT="$PWD/build" $XCODEBUILD_SETTINGS
36 |
37 | echo "*** Building..."
38 | xcodebuild -configuration "$XCCONFIGURATION" -scheme ReactiveCocoa test OBJROOT="$PWD/build" SYMROOT="$PWD/build" $XCODEBUILD_SETTINGS || exit $?
39 | xcodebuild -configuration "$XCCONFIGURATION" -scheme ReactiveCocoa-iOS build OBJROOT="$PWD/build" SYMROOT="$PWD/build" $XCODEBUILD_SETTINGS || exit $?
40 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIControl+RACSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+RACSignalSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "UIControl+RACSignalSupport.h"
10 | #import "RACEventTrampoline.h"
11 | #import
12 |
13 | @implementation UIControl (RACSignalSupport)
14 |
15 | - (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents {
16 | RACEventTrampoline *trampoline = [RACEventTrampoline trampolineForControl:self controlEvents:controlEvents];
17 | [trampoline.subject setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", self, (unsigned long)controlEvents];
18 |
19 | NSMutableSet *controlEventTrampolines = objc_getAssociatedObject(self, RACEventTrampolinesKey);
20 | if (controlEventTrampolines == nil) {
21 | controlEventTrampolines = [NSMutableSet set];
22 | objc_setAssociatedObject(self, RACEventTrampolinesKey, controlEventTrampolines, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
23 | }
24 |
25 | [controlEventTrampolines addObject:trampoline];
26 |
27 | return trampoline.subject;
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/RACExtensions/NSFileHandle+RACSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSFileHandle+RACSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/10/12.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSFileHandle+RACSupport.h"
10 | #import "NSNotificationCenter+RACSupport.h"
11 |
12 | @implementation NSFileHandle (RACSupport)
13 |
14 | - (RACSignal *)rac_readInBackground {
15 | RACReplaySubject *subject = [RACReplaySubject subject];
16 | [subject setNameWithFormat:@"%@ -rac_readInBackground", self];
17 |
18 | RACSignal *dataNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:NSFileHandleReadCompletionNotification object:self] map:^(NSNotification *note) {
19 | return [note.userInfo objectForKey:NSFileHandleNotificationDataItem];
20 | }];
21 |
22 | __block RACDisposable *subscription = [dataNotification subscribeNext:^(NSData *data) {
23 | if(data.length > 0) {
24 | [subject sendNext:data];
25 | [self readInBackgroundAndNotify];
26 | } else {
27 | [subject sendCompleted];
28 | [subscription dispose];
29 | }
30 | }];
31 |
32 | [self readInBackgroundAndNotify];
33 |
34 | return subject;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSObjectRACDeallocatingSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACDeallocating.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Kazuo Koga on 2013/03/15.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACDeallocating.h"
10 | #import "RACTestObject.h"
11 | #import "RACSignal+Operations.h"
12 |
13 | SpecBegin(NSObjectRACDeallocatingSpec)
14 |
15 | describe(@"-rac_didDeallocSignal", ^{
16 | it(@"should complete on dealloc", ^{
17 | __block BOOL completed = NO;
18 | @autoreleasepool {
19 | [[[[RACTestObject alloc] init] rac_didDeallocSignal] subscribeCompleted:^{
20 | completed = YES;
21 | }];
22 | }
23 |
24 | expect(completed).to.beTruthy();
25 | });
26 |
27 | it(@"should not send anything", ^{
28 | __block BOOL valueReceived = NO;
29 | __block BOOL completed = NO;
30 | @autoreleasepool {
31 | [[[[RACTestObject alloc] init] rac_didDeallocSignal] subscribeNext:^(id x) {
32 | valueReceived = YES;
33 | } completed:^{
34 | completed = YES;
35 | }];
36 | }
37 |
38 | expect(valueReceived).to.beFalsy();
39 | expect(completed).to.beTruthy();
40 | });
41 | });
42 |
43 | SpecEnd
44 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACScheduler+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACScheduler+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/29/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // The queue-specific current scheduler key.
12 | extern const void *RACSchedulerCurrentSchedulerKey;
13 |
14 | // A private interface for internal RAC use only.
15 | @interface RACScheduler ()
16 |
17 | // A dedicated scheduler that fills two requirements:
18 | //
19 | // 1. By the time subscription happens, we need a valid +currentScheduler.
20 | // 2. Subscription should happen as soon as possible.
21 | //
22 | // To fulfill those two, if we already have a valid +currentScheduler, it
23 | // immediately executes scheduled blocks. If we don't, it will execute scheduled
24 | // blocks with a private background scheduler.
25 | + (instancetype)subscriptionScheduler;
26 |
27 | // Initializes the receiver with the given name.
28 | //
29 | // name - The name of the scheduler. If nil, a default name will be used.
30 | //
31 | // Returns the initialized object.
32 | - (id)initWithName:(NSString *)name;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSubscriptingAssignmentTrampolineSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriptingAssignmentTrampolineSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 9/24/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubscriptingAssignmentTrampoline.h"
10 | #import "RACPropertySignalExamples.h"
11 | #import "RACTestObject.h"
12 | #import "RACSubject.h"
13 |
14 | SpecBegin(RACSubscriptingAssignmentTrampoline)
15 |
16 | id setupBlock = ^(RACTestObject *testObject, NSString *keyPath, RACSignal *signal) {
17 | [RACSubscriptingAssignmentTrampoline trampoline][ [[RACSubscriptingAssignmentObjectKeyPathPair alloc] initWithObject:testObject keyPath:keyPath] ] = signal;
18 | };
19 |
20 | itShouldBehaveLike(RACPropertySignalExamples, ^{
21 | return @{ RACPropertySignalExamplesSetupBlock: setupBlock };
22 | });
23 |
24 | it(@"should expand the RAC macro properly", ^{
25 | RACSubject *subject = [RACSubject subject];
26 | RACTestObject *testObject = [[RACTestObject alloc] init];
27 | RAC(testObject, objectValue) = subject;
28 |
29 | [subject sendNext:@1];
30 | expect(testObject.objectValue).to.equal(@1);
31 | });
32 |
33 | SpecEnd
34 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSControl+RACTextSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSControl+RACTextSignalSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-03-08.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSControl+RACTextSignalSupport.h"
10 | #import "EXTScope.h"
11 | #import "RACDisposable.h"
12 | #import "RACSignal.h"
13 | #import "RACSubscriber.h"
14 |
15 | @implementation NSControl (RACTextSignalSupport)
16 |
17 | - (RACSignal *)rac_textSignal {
18 | @weakify(self);
19 | return [[[[RACSignal
20 | createSignal:^(id subscriber) {
21 | @strongify(self);
22 | id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSControlTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) {
23 | [subscriber sendNext:note.object];
24 | }];
25 |
26 | return [RACDisposable disposableWithBlock:^{
27 | [NSNotificationCenter.defaultCenter removeObserver:observer];
28 | }];
29 | }]
30 | map:^(NSControl *control) {
31 | return [control.stringValue copy];
32 | }]
33 | startWith:[self.stringValue copy]]
34 | setNameWithFormat:@"%@ -rac_textSignal", self];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSDictionary+RACSequenceAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+RACSequenceAdditions.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSequence;
12 |
13 | @interface NSDictionary (RACSequenceAdditions)
14 |
15 | // Creates and returns a sequence of RACTuple key/value pairs. The key will be
16 | // the first element in the tuple, and the value will be the second.
17 | //
18 | // Mutating the receiver will not affect the sequence after it's been created.
19 | @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
20 |
21 | // Creates and returns a sequence corresponding to the keys in the receiver.
22 | //
23 | // Mutating the receiver will not affect the sequence after it's been created.
24 | @property (nonatomic, copy, readonly) RACSequence *rac_keySequence;
25 |
26 | // Creates and returns a sequence corresponding to the values in the receiver.
27 | //
28 | // Mutating the receiver will not affect the sequence after it's been created.
29 | @property (nonatomic, copy, readonly) RACSequence *rac_valueSequence;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACObjCRuntime.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACObjCRuntime.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/19/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACObjCRuntime.h"
10 |
11 | @implementation RACObjCRuntime
12 |
13 | + (void)findMethod:(SEL)method inProtocol:(Protocol *)protocol outMethod:(struct objc_method_description *)outMethod {
14 | // First, we look for a @required method. If none is found, we look for an
15 | // @optional method.
16 | *outMethod = protocol_getMethodDescription(protocol, method, YES, YES);
17 | if (outMethod->name == NULL) {
18 | *outMethod = protocol_getMethodDescription(protocol, method, NO, YES);
19 | }
20 | }
21 |
22 | + (const char *)getMethodTypesForMethod:(SEL)method inProtocol:(Protocol *)protocol {
23 | struct objc_method_description desc;
24 | [self findMethod:method inProtocol:protocol outMethod:&desc];
25 | return desc.types;
26 | }
27 |
28 | + (BOOL)method:(SEL)method existsInProtocol:(Protocol *)protocol {
29 | struct objc_method_description desc;
30 | [self findMethod:method inProtocol:protocol outMethod:&desc];
31 | return desc.name != NULL;
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBinding+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBinding+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 01/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACBinding.h"
10 |
11 | @interface RACBinding ()
12 |
13 | // Designated initializer.
14 | //
15 | // signal - A signal of `RACTuple`s where the first element is the value of
16 | // the binding's property as it changes, and the second element is
17 | // the `RACBinding` that triggered the change, or `nil` if the
18 | // change was triggered by other means. The signal must also send a
19 | // `RACTuple` with the current value and it's originator on
20 | // subscription.
21 | // subscriber - A subscriber that will be sent a `RACTuple` every time the
22 | // binding's property is changed. The first element will be the new
23 | // value, the second element will be the `RACBinding` that
24 | // triggered the change or nil if the change was triggered by the
25 | // property itself.
26 | - (instancetype)initWithSignal:(RACSignal *)signal subscriber:(id)subscriber;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACKVOTrampoline.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACKVOTrampoline.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 1/15/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "NSObject+RACKVOWrapper.h"
11 |
12 | // The KVO trampoline object. Represents a KVO observation.
13 | @interface RACKVOTrampoline : NSObject
14 |
15 | // Initializes the receiver with the given parameters.
16 | //
17 | // target - The object whose key path should be observed. Cannot be nil.
18 | // observer - The object that gets notified when the value at the key path
19 | // changes. Can be nil.
20 | // keyPath - The key path on `target` to observe. Cannot be nil.
21 | // options - Any key value observing options to use in the observation.
22 | // block - The block to call when the value at the observed key path changes.
23 | // Cannot be nil.
24 | //
25 | // Returns the initialized object.
26 | - (id)initWithTarget:(NSObject *)target observer:(NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block;
27 |
28 | // Stop the KVO observation.
29 | - (void)stopObserving;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACPropertySubject+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySubject+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 31/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACPropertySubject.h"
10 |
11 | @class RACSignal;
12 | @protocol RACSubscriber;
13 |
14 | @interface RACPropertySubject ()
15 |
16 | // Designated initializer.
17 | //
18 | // signal - A signal of `RACTuple`s where the first element is the value of
19 | // the property as it changes, and the second element is the
20 | // binding that triggered the change, or `nil` if the change was
21 | // triggered by other means. The signal must also send a `RACTuple`
22 | // with the current value and it's originator on subscription.
23 | // subscriber - A subscriber that will be sent a `RACTuple` every time the
24 | // property is changed. The first element will be the new value,
25 | // the second element will be the binding that triggered the change
26 | // or nil if the change was triggered by the property itself.
27 | - (instancetype)initWithSignal:(RACSignal *)signal subscriber:(id)subscriber;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSStringRACKeyPathUtilitiesSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSStringRACKeyPathUtilitiesSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 05/05/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSString+RACKeyPathUtilities.h"
10 |
11 | SpecBegin(NSStringRACKeyPathUtilities)
12 |
13 | describe(@"-keyPathComponents", ^{
14 | it(@"should return components in the key path", ^{
15 | expect(@"self.test.key.path".rac_keyPathComponents).to.equal((@[@"self", @"test", @"key", @"path"]));
16 | });
17 |
18 | it(@"should return nil if given an empty string", ^{
19 | expect(@"".rac_keyPathComponents).to.beNil();
20 | });
21 | });
22 |
23 | describe(@"-keyPathByDeletingLastKeyPathComponent", ^{
24 | it(@"should return the parent key path", ^{
25 | expect(@"grandparent.parent.child".rac_keyPathByDeletingLastKeyPathComponent).to.equal(@"grandparent.parent");
26 | });
27 |
28 | it(@"should return nil if given an empty string", ^{
29 | expect(@"".rac_keyPathByDeletingLastKeyPathComponent).to.beNil();
30 | });
31 |
32 | it(@"should return nil if given a key path with only one component", ^{
33 | expect(@"self".rac_keyPathByDeletingLastKeyPathComponent).to.beNil();
34 | });
35 | });
36 |
37 | SpecEnd
38 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriptionScheduler.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriptionScheduler.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubscriptionScheduler.h"
10 | #import "RACScheduler+Private.h"
11 |
12 | @interface RACSubscriptionScheduler ()
13 |
14 | // A private background scheduler on which to subscribe if the +currentScheduler
15 | // is unknown.
16 | @property (nonatomic, strong, readonly) RACScheduler *backgroundScheduler;
17 |
18 | @end
19 |
20 | @implementation RACSubscriptionScheduler
21 |
22 | #pragma mark Lifecycle
23 |
24 | - (id)init {
25 | self = [super initWithName:@"com.ReactiveCocoa.RACScheduler.subscriptionScheduler"];
26 | if (self == nil) return nil;
27 |
28 | _backgroundScheduler = [RACScheduler scheduler];
29 |
30 | return self;
31 | }
32 |
33 | #pragma mark RACScheduler
34 |
35 | - (RACDisposable *)schedule:(void (^)(void))block {
36 | NSCParameterAssert(block != NULL);
37 |
38 | if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
39 |
40 | block();
41 | return nil;
42 | }
43 |
44 | - (RACDisposable *)after:(dispatch_time_t)when schedule:(void (^)(void))block {
45 | RACScheduler *scheduler = RACScheduler.currentScheduler ?: self.backgroundScheduler;
46 | return [scheduler after:when schedule:block];
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UITextView+RACSignalSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITextView+RACSignalSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/18/12.
6 | // Copyright (c) 2012 Cody Krieger. All rights reserved.
7 | //
8 |
9 | #import "UITextView+RACSignalSupport.h"
10 | #import "RACEventTrampoline.h"
11 | #import
12 |
13 | @implementation UITextView (RACSignalSupport)
14 |
15 | - (RACSignal *)rac_signalForDelegateMethod:(SEL)method {
16 | RACEventTrampoline *trampoline = [RACEventTrampoline trampolineForTextView:self delegateMethod:method];
17 | [trampoline.subject setNameWithFormat:@"%@ -rac_signalForDelegateMethod: (%@)", self, NSStringFromSelector(method)];
18 |
19 | NSMutableSet *controlEventTrampolines = objc_getAssociatedObject(self, RACEventTrampolinesKey);
20 | if (controlEventTrampolines == nil) {
21 | controlEventTrampolines = [NSMutableSet set];
22 | objc_setAssociatedObject(self, RACEventTrampolinesKey, controlEventTrampolines, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
23 | }
24 |
25 | [controlEventTrampolines addObject:trampoline];
26 |
27 | return trampoline.subject;
28 | }
29 |
30 | - (RACSignal *)rac_textSignal {
31 | return [[[[self rac_signalForDelegateMethod:@selector(textViewDidChange:)]
32 | map:^(UITextView *x) {
33 | return x.text;
34 | }]
35 | startWith:self.text]
36 | setNameWithFormat:@"%@ -rac_textSignal", self];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACBlockTrampolineSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACBlockTrampolineSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 10/28/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACBlockTrampoline.h"
10 | #import "RACTuple.h"
11 |
12 | SpecBegin(RACBlockTrampoline)
13 |
14 | it(@"should invoke the block with the given arguments", ^{
15 | __block NSString *stringArg;
16 | __block NSNumber *numberArg;
17 | id (^block)(NSString *, NSNumber *) = ^ id (NSString *string, NSNumber *number) {
18 | stringArg = string;
19 | numberArg = number;
20 | return nil;
21 | };
22 |
23 | [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(@"hi", @1)];
24 | expect(stringArg).to.equal(@"hi");
25 | expect(numberArg).to.equal(@1);
26 | });
27 |
28 | it(@"should return the result of the block invocation", ^{
29 | NSString * (^block)(NSString *) = ^(NSString *string) {
30 | return string.uppercaseString;
31 | };
32 |
33 | NSString *result = [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(@"hi")];
34 | expect(result).to.equal(@"HI");
35 | });
36 |
37 | it(@"should pass RACTupleNils as nil", ^{
38 | __block id arg;
39 | id (^block)(id) = ^ id (id obj) {
40 | arg = obj;
41 | return nil;
42 | };
43 |
44 | [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(nil)];
45 | expect(arg).to.beNil();
46 | });
47 |
48 | SpecEnd
49 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACSelectorSignal.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACSelectorSignal.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/18/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACSignal;
12 |
13 | @interface NSObject (RACSelectorSignal)
14 |
15 | // Adds an implementation of `selector` to the receiver which will send the
16 | // argument each time it is invoked. The receiver itself shouldn't have an
17 | // existing implementation of `selector`. It will not swizzle or replace any
18 | // existing implementation. Superclass implementations are allowed but they
19 | // won't be called.
20 | //
21 | // This is most useful for implementing a method which is called to communicate
22 | // events to the receiver. For example, in an NSView:
23 | // [someSignal takeUntil:[self rac_signalForSelector:@selector(mouseDown:)]];
24 | //
25 | // selector - The selector for which an implementation should be added. It
26 | // shouldn't already be implemented on the receiver. It must be of
27 | // the type:
28 | // - (void)selector:(id)argument
29 | //
30 | // Returns a signal which will send the argument on each invocation.
31 | - (RACSignal *)rac_signalForSelector:(SEL)selector;
32 |
33 | // The same as -rac_signalForSelector: but with class methods.
34 | + (RACSignal *)rac_signalForSelector:(SEL)selector;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACAppKitBindings.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACAppKitBindings.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface NSObject (RACAppKitBindings)
13 |
14 | // Calls -[NSObject bind:binding toObject:object withKeyPath:keyPath options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption, nil]]
15 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath;
16 |
17 | // Calls -[NSObject bind:binding toObject:object withKeyPath:keyPath options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption, nilValue, NSNullPlaceholderBindingOption, nil]];
18 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath nilValue:(id)nilValue;
19 |
20 | // Same as `-[NSObject bind:toObject:withKeyPath:] but also transforms values
21 | // using the given transform block.
22 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath transform:(id (^)(id value))transformBlock;
23 |
24 | // Same as `-[NSObject bind:toObject:withKeyPath:] but the value is transformed
25 | // by negating it.
26 | - (void)rac_bind:(NSString *)binding toObject:(id)object withNegatedKeyPath:(NSString *)keyPath;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACKVOWrapper.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACKVOWrapper.h
3 | // GitHub
4 | //
5 | // Created by Josh Abernathy on 10/11/11.
6 | // Copyright (c) 2011 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // The block called when the KVO notification fires.
12 | //
13 | // target - The object being observed.
14 | // observer - The object doing the observing.
15 | // change - The KVO change dictionary, as given to
16 | // -observeValueForKeyPath:ofObject:change:context:.
17 | typedef void (^RACKVOBlock)(id target, id observer, NSDictionary *change);
18 |
19 | @class RACKVOTrampoline;
20 |
21 | @interface NSObject (RACKVOWrapper)
22 |
23 | // Adds the given block as the callback for when the keyPath changes. The
24 | // observer does not need to be explicitly removed. It will be removed when the
25 | // observer or observed object is dealloc'd.
26 | //
27 | // observer - the object to which callbacks will be delivered. This is passed back
28 | // into the given block.
29 | //
30 | // keyPath - the key path to observe
31 | //
32 | // options - the key-value observing options
33 | //
34 | // block - the block called when the value at the key path changes.
35 | //
36 | // Returns the KVO trampoline that can be used to stop the observation.
37 | - (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBehaviorSubject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACBehaviorSubject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/16/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACBehaviorSubject.h"
10 | #import "RACDisposable.h"
11 | #import "RACScheduler+Private.h"
12 |
13 | @interface RACBehaviorSubject ()
14 |
15 | // This property should only be used while synchronized on self.
16 | @property (nonatomic, strong) id currentValue;
17 |
18 | @end
19 |
20 | @implementation RACBehaviorSubject
21 |
22 | #pragma mark Lifecycle
23 |
24 | + (instancetype)behaviorSubjectWithDefaultValue:(id)value {
25 | RACBehaviorSubject *subject = [self subject];
26 | subject.currentValue = value;
27 | return subject;
28 | }
29 |
30 | #pragma mark RACSignal
31 |
32 | - (RACDisposable *)subscribe:(id)subscriber {
33 | RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
34 |
35 | RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
36 | @synchronized (self) {
37 | [subscriber sendNext:self.currentValue];
38 | }
39 | }];
40 |
41 | return [RACDisposable disposableWithBlock:^{
42 | [subscriptionDisposable dispose];
43 | [schedulingDisposable dispose];
44 | }];
45 | }
46 |
47 | #pragma mark RACSubscriber
48 |
49 | - (void)sendNext:(id)value {
50 | @synchronized (self) {
51 | self.currentValue = value;
52 | [super sendNext:value];
53 | }
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSControl+RACCommandSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSControl+RACCommandSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/3/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSControl+RACCommandSupport.h"
10 | #import "RACCommand.h"
11 |
12 | #import
13 |
14 | static void * NSControlRACCommandKey = &NSControlRACCommandKey;
15 |
16 | @implementation NSControl (RACCommandSupport)
17 |
18 | - (RACCommand *)rac_command {
19 | return objc_getAssociatedObject(self, NSControlRACCommandKey);
20 | }
21 |
22 | - (void)setRac_command:(RACCommand *)command {
23 | objc_setAssociatedObject(self, NSControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
24 |
25 | [self unbind:NSEnabledBinding];
26 | self.enabled = command != nil ? command.canExecute : YES;
27 |
28 | if (command == nil) return;
29 |
30 | [self bind:NSEnabledBinding toObject:self.rac_command withKeyPath:@"canExecute" options:nil];
31 |
32 | [self rac_hijackActionAndTargetIfNeeded];
33 | }
34 |
35 | - (void)rac_hijackActionAndTargetIfNeeded {
36 | SEL hijackSelector = @selector(rac_commandPerformAction:);
37 | if (self.target == self && self.action == hijackSelector) return;
38 |
39 | if (self.target != nil) NSLog(@"WARNING: NSControl.rac_command hijacks the control's existing target and action.");
40 |
41 | self.target = self;
42 | self.action = hijackSelector;
43 | }
44 |
45 | - (void)rac_commandPerformAction:(id)sender {
46 | [self.rac_command execute:sender];
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACTestObject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACTestObject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 9/18/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACTestObject.h"
10 |
11 | @implementation RACTestObject
12 |
13 | - (void)setNilValueForKey:(NSString *)key {
14 | [self setValue:@0 forKey:key];
15 | }
16 |
17 | - (void)setObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue {
18 | self.hasInvokedSetObjectValueAndIntegerValue = YES;
19 | self.objectValue = objectValue;
20 | self.integerValue = integerValue;
21 | }
22 |
23 | - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue {
24 | self.hasInvokedSetObjectValueAndSecondObjectValue = YES;
25 | self.objectValue = objectValue;
26 | self.secondObjectValue = secondObjectValue;
27 | }
28 |
29 | - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue {
30 | return [NSString stringWithFormat:@"%@: %ld", objectValue, (long)integerValue];
31 | }
32 |
33 | - (NSString *)combineObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue {
34 | return [NSString stringWithFormat:@"%@: %@", objectValue, secondObjectValue];
35 | }
36 |
37 | - (void)lifeIsGood:(id)sender {
38 |
39 | }
40 |
41 | + (void)lifeIsGood:(id)sender {
42 |
43 | }
44 |
45 | - (NSRange)returnRangeValueWithObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue {
46 | return NSMakeRange((NSUInteger)[objectValue integerValue], (NSUInteger)integerValue);
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBacktrace+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACBacktrace+Private.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-12-24.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // When this header is imported in RAC sources, any uses of GCD dispatches (in
12 | // Debug builds) will automatically use the backtrace-logging overrides instead.
13 | #ifdef DEBUG
14 |
15 | void rac_dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
16 | void rac_dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
17 | void rac_dispatch_after(dispatch_time_t time, dispatch_queue_t queue, dispatch_block_t block);
18 | void rac_dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t function);
19 | void rac_dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t function);
20 | void rac_dispatch_after_f(dispatch_time_t time, dispatch_queue_t queue, void *context, dispatch_function_t function);
21 |
22 | #define dispatch_async(...) \
23 | rac_dispatch_async(__VA_ARGS__)
24 |
25 | #define dispatch_barrier_async(...) \
26 | rac_dispatch_barrier_async(__VA_ARGS__)
27 |
28 | #define dispatch_after(...) \
29 | rac_dispatch_after(__VA_ARGS__)
30 |
31 | #define dispatch_async_f(...) \
32 | rac_dispatch_async_f(__VA_ARGS__)
33 |
34 | #define dispatch_barrier_async_f(...) \
35 | rac_dispatch_barrier_async_f(__VA_ARGS__)
36 |
37 | #define dispatch_after_f(...) \
38 | rac_dispatch_after_f(__VA_ARGS__)
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriptingAssignmentTrampoline.m
3 | // iOSDemo
4 | //
5 | // Created by Josh Abernathy on 9/24/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubscriptingAssignmentTrampoline.h"
10 |
11 | @interface RACSubscriptingAssignmentObjectKeyPathPair ()
12 | @property (nonatomic, readonly, strong) NSObject *object;
13 | @property (nonatomic, readonly, copy) NSString *keyPath;
14 | @end
15 |
16 | @implementation RACSubscriptingAssignmentObjectKeyPathPair
17 |
18 | #pragma mark NSCopying
19 |
20 | - (id)copyWithZone:(NSZone *)zone {
21 | return self;
22 | }
23 |
24 | #pragma mark API
25 |
26 | - (id)initWithObject:(NSObject *)object keyPath:(NSString *)keyPath {
27 | self = [super init];
28 | if (self == nil) return nil;
29 |
30 | _object = object;
31 | _keyPath = [keyPath copy];
32 |
33 | return self;
34 | }
35 |
36 | @end
37 |
38 | @implementation RACSubscriptingAssignmentTrampoline
39 |
40 | #pragma mark API
41 |
42 | + (instancetype)trampoline {
43 | static dispatch_once_t onceToken;
44 | static RACSubscriptingAssignmentTrampoline *trampoline = nil;
45 | dispatch_once(&onceToken, ^{
46 | trampoline = [[self alloc] init];
47 | });
48 |
49 | return trampoline;
50 | }
51 |
52 | - (void)setObject:(RACSignal *)signal forKeyedSubscript:(RACSubscriptingAssignmentObjectKeyPathPair *)pair {
53 | NSCParameterAssert([pair isKindOfClass:RACSubscriptingAssignmentObjectKeyPathPair.class]);
54 |
55 | [pair.object rac_deriveProperty:pair.keyPath from:signal];
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/9/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubject.h"
10 | #import "EXTScope.h"
11 | #import "RACSignal+Private.h"
12 | #import "RACCompoundDisposable.h"
13 |
14 | @interface RACSubject ()
15 |
16 | @property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
17 |
18 | @end
19 |
20 | @implementation RACSubject
21 |
22 | #pragma mark Lifecycle
23 |
24 | + (instancetype)subject {
25 | return [[self alloc] init];
26 | }
27 |
28 | - (id)init {
29 | self = [super init];
30 | if (self == nil) return nil;
31 |
32 | _disposable = [RACCompoundDisposable compoundDisposable];
33 |
34 | return self;
35 | }
36 |
37 | - (void)dealloc {
38 | [self.disposable dispose];
39 | }
40 |
41 | #pragma mark RACSubscriber
42 |
43 | - (void)sendNext:(id)value {
44 | [self performBlockOnEachSubscriber:^(id subscriber) {
45 | [subscriber sendNext:value];
46 | }];
47 | }
48 |
49 | - (void)sendError:(NSError *)error {
50 | [self.disposable dispose];
51 |
52 | [self performBlockOnEachSubscriber:^(id subscriber) {
53 | [subscriber sendError:error];
54 | }];
55 | }
56 |
57 | - (void)sendCompleted {
58 | [self.disposable dispose];
59 |
60 | [self performBlockOnEachSubscriber:^(id subscriber) {
61 | [subscriber sendCompleted];
62 | }];
63 | }
64 |
65 | - (void)didSubscribeWithDisposable:(RACDisposable *)d {
66 | if (d != nil) [self.disposable addDisposable:d];
67 | }
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriptingAssignmentTrampoline.h
3 | // iOSDemo
4 | //
5 | // Created by Josh Abernathy on 9/24/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 | // Lets you assign a keypath / property to a signal. The value of the keypath or
14 | // property is then kept up-to-date with the latest value from the signal.
15 | //
16 | // If given just one argument, it's assumed to be a keypath or property on self.
17 | // If given two, the first argument is the object to which the keypath is
18 | // relative and the second is the keypath.
19 | //
20 | // Examples:
21 | //
22 | // RAC(self.blah) = someSignal;
23 | // RAC(otherObject, blah) = someSignal;
24 | #define RAC(...) metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(_RAC_OBJ(self, __VA_ARGS__))(_RAC_OBJ(__VA_ARGS__))
25 |
26 | // Do not use this directly. Use the RAC macro above.
27 | #define _RAC_OBJ(OBJ, KEYPATH) [RACSubscriptingAssignmentTrampoline trampoline][ [[RACSubscriptingAssignmentObjectKeyPathPair alloc] initWithObject:OBJ keyPath:@keypath(OBJ, KEYPATH)] ]
28 |
29 | @interface RACSubscriptingAssignmentObjectKeyPathPair : NSObject
30 |
31 | - (id)initWithObject:(NSObject *)object keyPath:(NSString *)keyPath;
32 |
33 | @end
34 |
35 | @interface RACSubscriptingAssignmentTrampoline : NSObject
36 |
37 | + (instancetype)trampoline;
38 | - (void)setObject:(RACSignal *)signal forKeyedSubscript:(id)key;
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEmptySequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACEmptySequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "RACEmptySequence.h"
10 |
11 | @implementation RACEmptySequence
12 |
13 | #pragma mark Lifecycle
14 |
15 | + (instancetype)empty {
16 | static id singleton;
17 | static dispatch_once_t pred;
18 |
19 | dispatch_once(&pred, ^{
20 | singleton = [[self alloc] init];
21 | });
22 |
23 | return singleton;
24 | }
25 |
26 | #pragma mark RACSequence
27 |
28 | - (id)head {
29 | return nil;
30 | }
31 |
32 | - (RACSequence *)tail {
33 | return nil;
34 | }
35 |
36 | - (RACSequence *)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
37 | return passthroughSequence ?: self;
38 | }
39 |
40 | #pragma mark NSCoding
41 |
42 | - (Class)classForCoder {
43 | // Empty sequences should be encoded as themselves, not array sequences.
44 | return self.class;
45 | }
46 |
47 | - (id)initWithCoder:(NSCoder *)coder {
48 | // Return the singleton.
49 | return self.class.empty;
50 | }
51 |
52 | - (void)encodeWithCoder:(NSCoder *)coder {
53 | }
54 |
55 | #pragma mark NSObject
56 |
57 | - (NSString *)description {
58 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@ }", self.class, self, self.name];
59 | }
60 |
61 | - (NSUInteger)hash {
62 | // This hash isn't ideal, but it's better than -[RACSequence hash], which
63 | // would just be zero because we have no head.
64 | return (NSUInteger)(__bridge void *)self;
65 | }
66 |
67 | - (BOOL)isEqual:(RACSequence *)seq {
68 | return (self == seq);
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSInvocation+RACTypeParsing.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSInvocation+RACTypeParsing.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSInvocation (RACTypeParsing)
12 |
13 | // Sets the argument for the invocation at the given index by unboxing the given
14 | // object based on the type signature of the argument.
15 | //
16 | // This does not support C array, union, or struct types other than CGRect,
17 | // CGSize, CGPoint, and NSRange.
18 | //
19 | // object - The object to unbox and set as the argument.
20 | // index - The index of the argument to set.
21 | - (void)rac_setArgument:(id)object atIndex:(NSUInteger)index;
22 |
23 | // Gets the argument for the invocation at the given index based on the
24 | // invocation's method signature. The value is then wrapped in the appropriate
25 | // object type.
26 | //
27 | // This does not support C array, union, or struct types other than CGRect,
28 | // CGSize, CGPoint, and NSRange.
29 | //
30 | // index - The index of the argument to get.
31 | //
32 | // Returns the argument of the invocation, wrapped in an object.
33 | - (id)rac_argumentAtIndex:(NSUInteger)index;
34 |
35 | // Gets the return value from the invocation based on the invocation's method
36 | // signature. The value is then wrapped in the appropriate object type.
37 | //
38 | // This does not support C array, union, or struct types other than CGRect,
39 | // CGSize, CGPoint, and NSRange.
40 | //
41 | // Returns the return value of the invocation, wrapped in an object. Voids are
42 | // returned as `RACUnit.defaultUnit`.
43 | - (id)rac_returnValue;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACDisposable.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACDisposable.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/16/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACDisposable.h"
10 | #import "RACScopedDisposable.h"
11 | #import
12 |
13 | @interface RACDisposable () {
14 | // A copied block of type void (^)(void) containing the logic for disposal,
15 | // or NULL if the receiver is already disposed.
16 | //
17 | // This should only be used atomically.
18 | void * volatile _disposeBlock;
19 | }
20 |
21 | @end
22 |
23 | @implementation RACDisposable
24 |
25 | #pragma mark Lifecycle
26 |
27 | + (instancetype)disposableWithBlock:(void (^)(void))block {
28 | RACDisposable *disposable = [[self alloc] init];
29 |
30 | id copiedBlock = [block copy];
31 | disposable->_disposeBlock = (void *)CFBridgingRetain(copiedBlock);
32 |
33 | // Force the store to _disposeBlock to complete.
34 | OSMemoryBarrier();
35 |
36 | return disposable;
37 | }
38 |
39 | - (void)dealloc {
40 | if (_disposeBlock != NULL) {
41 | CFRelease(_disposeBlock);
42 | _disposeBlock = NULL;
43 | }
44 | }
45 |
46 | #pragma mark Disposal
47 |
48 | - (void)dispose {
49 | void (^disposeBlock)(void) = NULL;
50 |
51 | while (YES) {
52 | void *blockPtr = _disposeBlock;
53 | if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
54 | disposeBlock = CFBridgingRelease(blockPtr);
55 | break;
56 | }
57 | }
58 |
59 | if (disposeBlock != nil) disposeBlock();
60 | }
61 |
62 | #pragma mark Scoped Disposables
63 |
64 | - (RACScopedDisposable *)asScopedDisposable {
65 | return [RACScopedDisposable scopedDisposableWithDisposable:self];
66 | }
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACTestObject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACTestObject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 9/18/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface RACTestObject : NSObject
12 |
13 | @property (nonatomic, strong) id objectValue;
14 | @property (nonatomic, strong) id secondObjectValue;
15 | @property (nonatomic, assign) NSInteger integerValue;
16 | @property (nonatomic, assign) char *charPointerValue;
17 | @property (nonatomic, assign) const char *constCharPointerValue;
18 | @property (nonatomic, assign) CGRect rectValue;
19 | @property (nonatomic, assign) CGSize sizeValue;
20 | @property (nonatomic, assign) CGPoint pointValue;
21 | @property (nonatomic, assign) NSRange rangeValue;
22 |
23 | // Has -setObjectValue:andIntegerValue: been called?
24 | @property (nonatomic, assign) BOOL hasInvokedSetObjectValueAndIntegerValue;
25 |
26 | // Has -setObjectValue:andSecondObjectValue: been called?
27 | @property (nonatomic, assign) BOOL hasInvokedSetObjectValueAndSecondObjectValue;
28 |
29 | - (void)setObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue;
30 | - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue;
31 |
32 | // Returns a string of the form "objectValue: integerValue".
33 | - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue;
34 | - (NSString *)combineObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue;
35 |
36 | - (void)lifeIsGood:(id)sender;
37 |
38 | + (void)lifeIsGood:(id)sender;
39 |
40 | - (NSRange)returnRangeValueWithObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACAppKitBindings.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACAppKitBindings.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/17/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACAppKitBindings.h"
10 | #import "RACValueTransformer.h"
11 |
12 |
13 | @implementation NSObject (RACAppKitBindings)
14 |
15 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath {
16 | [self rac_bind:binding toObject:object withKeyPath:keyPath nilValue:nil];
17 | }
18 |
19 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath nilValue:(id)nilValue {
20 | [self bind:binding toObject:object withKeyPath:keyPath options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption, nilValue, NSNullPlaceholderBindingOption, nil]];
21 | }
22 |
23 | - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath transform:(id (^)(id value))transformBlock {
24 | RACValueTransformer *transformer = [RACValueTransformer transformerWithBlock:transformBlock];
25 | [self bind:binding toObject:object withKeyPath:keyPath options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption, transformer, NSValueTransformerBindingOption, nil]];
26 | }
27 |
28 | - (void)rac_bind:(NSString *)binding toObject:(id)object withNegatedKeyPath:(NSString *)keyPath {
29 | [self bind:binding toObject:object withKeyPath:keyPath options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption, NSNegateBooleanTransformerName, NSValueTransformerNameBindingOption, nil]];
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEvent.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACEvent.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-01-07.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // Describes the type of a RACEvent.
12 | //
13 | // RACEventTypeCompleted - A `completed` event.
14 | // RACEventTypeError - An `error` event.
15 | // RACEventTypeNext - A `next` event.
16 | typedef enum : NSUInteger {
17 | RACEventTypeCompleted,
18 | RACEventTypeError,
19 | RACEventTypeNext
20 | } RACEventType;
21 |
22 | // Represents an event sent by a RACSignal.
23 | //
24 | // This corresponds to the `Notification` class in Rx.
25 | @interface RACEvent : NSObject
26 |
27 | // Returns a singleton RACEvent representing the `completed` event.
28 | + (instancetype)completedEvent;
29 |
30 | // Returns a new event of type RACEventTypeError, containing the given error.
31 | + (instancetype)eventWithError:(NSError *)error;
32 |
33 | // Returns a new event of type RACEventTypeNext, containing the given value.
34 | + (instancetype)eventWithValue:(id)value;
35 |
36 | // The type of event represented by the receiver.
37 | @property (nonatomic, assign, readonly) RACEventType eventType;
38 |
39 | // Returns whether the receiver is of type RACEventTypeCompleted or
40 | // RACEventTypeError.
41 | @property (nonatomic, getter = isFinished, assign, readonly) BOOL finished;
42 |
43 | // The error associated with an event of type RACEventTypeError. This will be
44 | // nil for all other event types.
45 | @property (nonatomic, strong, readonly) NSError *error;
46 |
47 | // The value associated with an event of type RACEventTypeNext. This will be
48 | // nil for all other event types.
49 | @property (nonatomic, strong, readonly) id value;
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACCompoundDisposable.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACCompoundDisposable.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // A disposable of disposables. When it is disposed, it disposes of all its
12 | // contained disposables.
13 | //
14 | // If -addDisposable: is called after the compound disposable has been disposed
15 | // of, the given disposable is immediately disposed. This allows a compound
16 | // disposable to act as a stand-in for a disposable that will be delivered
17 | // asynchronously.
18 | @interface RACCompoundDisposable : RACDisposable
19 |
20 | // Creates and returns a new compound disposable.
21 | + (instancetype)compoundDisposable;
22 |
23 | // Creates and returns a new compound disposable containing the given
24 | // disposables.
25 | + (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables;
26 |
27 | // Adds the given disposable. If the receiving disposable has already been
28 | // disposed of, the given disposable is disposed immediately.
29 | //
30 | // This method is thread-safe.
31 | //
32 | // disposable - The disposable to add. Cannot be nil.
33 | - (void)addDisposable:(RACDisposable *)disposable;
34 |
35 | // Removes the specified disposable from the compound disposable (regardless of
36 | // its disposed status), or does nothing if it's not in the compound disposable.
37 | //
38 | // This is mainly useful for limiting the memory usage of the compound
39 | // disposable for long-running operations.
40 | //
41 | // This method is thread-safe.
42 | //
43 | // disposable - The disposable to remove. This argument may be nil (to make the
44 | // use of weak references easier).
45 | - (void)removeDisposable:(RACDisposable *)disposable;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACMulticastConnection.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | @class RACSignal;
10 | @class RACDisposable;
11 |
12 | // A multicast connection encapsulates the idea of sharing one subscription to a
13 | // signal to many subscribers. This is most often needed if the subscription to
14 | // the underlying signal involves side-effects or shouldn't be called more than
15 | // once.
16 | //
17 | // The multicasted signal is only subscribed to when
18 | // -[RACMulticastConnection connect] is called. Until that happens, no values
19 | // will be sent on `signal`. See -[RACMulticastConnection autoconnect] for how
20 | // -[RACMulticastConnection connect] can be called automatically.
21 | //
22 | // Note that you shouldn't create RACMulticastConnection manually. Instead use
23 | // -[RACSignal publish] or -[RACSignal multicast:].
24 | @interface RACMulticastConnection : NSObject
25 |
26 | // The multicasted signal.
27 | @property (nonatomic, strong, readonly) RACSignal *signal;
28 |
29 | // Connect to the underlying signal by subscribing to it. Calling this multiple
30 | // times does nothing but return the existing connection's disposable.
31 | //
32 | // Returns the disposable for the subscription to the multicasted signal.
33 | - (RACDisposable *)connect;
34 |
35 | // Connects to the underlying signal when the returned signal is first
36 | // subscribed to, and disposes of the subscription to the multicasted signal
37 | // when the returned signal has no subscribers.
38 | //
39 | // If new subscribers show up after being disposed, they'll subscribe and then
40 | // be immediately disposed of. The returned signal will never re-connect to the
41 | // multicasted signal.
42 | //
43 | // Returns the autoconnecting signal.
44 | - (RACSignal *)autoconnect;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACStringSequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACStringSequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "RACStringSequence.h"
10 | #import "EXTScope.h"
11 |
12 | @interface RACStringSequence ()
13 |
14 | // The string being sequenced.
15 | @property (nonatomic, copy, readonly) NSString *string;
16 |
17 | // The index in the string from which the sequence starts.
18 | @property (nonatomic, assign, readonly) NSUInteger offset;
19 |
20 | @end
21 |
22 | @implementation RACStringSequence
23 |
24 | #pragma mark Lifecycle
25 |
26 | + (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset {
27 | NSCParameterAssert(offset <= string.length);
28 |
29 | if (offset == string.length) return self.empty;
30 |
31 | RACStringSequence *seq = [[self alloc] init];
32 | seq->_string = [string copy];
33 | seq->_offset = offset;
34 | return seq;
35 | }
36 |
37 | #pragma mark RACSequence
38 |
39 | - (id)head {
40 | return [self.string substringWithRange:NSMakeRange(self.offset, 1)];
41 | }
42 |
43 | - (RACSequence *)tail {
44 | RACSequence *sequence = [self.class sequenceWithString:self.string offset:self.offset + 1];
45 | sequence.name = self.name;
46 | return sequence;
47 | }
48 |
49 | - (NSArray *)array {
50 | NSUInteger substringLength = self.string.length - self.offset;
51 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:substringLength];
52 |
53 | [self.string enumerateSubstringsInRange:NSMakeRange(self.offset, substringLength) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
54 | [array addObject:substring];
55 | }];
56 |
57 | return [array copy];
58 | }
59 |
60 | #pragma mark NSObject
61 |
62 | - (NSString *)description {
63 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@, string = %@ }", self.class, self, self.name, [self.string substringFromIndex:self.offset]];
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSignalSequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSignalSequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-09.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSignalSequence.h"
10 | #import "RACDisposable.h"
11 | #import "RACReplaySubject.h"
12 | #import "RACSignal+Operations.h"
13 |
14 | @interface RACSignalSequence ()
15 |
16 | // Replays the signal given on initialization.
17 | @property (nonatomic, strong, readonly) RACReplaySubject *subject;
18 |
19 | @end
20 |
21 | @implementation RACSignalSequence
22 |
23 | #pragma mark Lifecycle
24 |
25 | + (RACSequence *)sequenceWithSignal:(RACSignal *)signal {
26 | RACSignalSequence *seq = [[self alloc] init];
27 |
28 | RACReplaySubject *subject = [RACReplaySubject subject];
29 | [signal subscribeNext:^(id value) {
30 | [subject sendNext:value];
31 | } error:^(NSError *error) {
32 | [subject sendError:error];
33 | } completed:^{
34 | [subject sendCompleted];
35 | }];
36 |
37 | seq->_subject = subject;
38 | return seq;
39 | }
40 |
41 | #pragma mark RACSequence
42 |
43 | - (id)head {
44 | id value = [self.subject firstOrDefault:self];
45 |
46 | if (value == self) {
47 | return nil;
48 | } else {
49 | return value ?: NSNull.null;
50 | }
51 | }
52 |
53 | - (RACSequence *)tail {
54 | RACSequence *sequence = [self.class sequenceWithSignal:[self.subject skip:1]];
55 | sequence.name = self.name;
56 | return sequence;
57 | }
58 |
59 | - (NSArray *)array {
60 | return self.subject.toArray;
61 | }
62 |
63 | #pragma mark NSObject
64 |
65 | - (NSString *)description {
66 | // Synchronously accumulate the values that have been sent so far.
67 | NSMutableArray *values = [NSMutableArray array];
68 | RACDisposable *disposable = [self.subject subscribeNext:^(id value) {
69 | @synchronized (values) {
70 | [values addObject:value ?: NSNull.null];
71 | }
72 | }];
73 |
74 | [disposable dispose];
75 |
76 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@, values = %@ … }", self.class, self, self.name, values];
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACMulticastConnection.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACMulticastConnection.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 4/11/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACMulticastConnection.h"
10 | #import "RACMulticastConnection+Private.h"
11 | #import "RACDisposable.h"
12 | #import "RACSubject.h"
13 | #import "RACSignal+Private.h"
14 |
15 | @interface RACMulticastConnection () {
16 | RACSubject *_signal;
17 | }
18 |
19 | @property (nonatomic, readonly, strong) RACSignal *sourceSignal;
20 | @property (strong) RACDisposable *disposable;
21 |
22 | // Should only be used while synchronized on self.
23 | @property (nonatomic, assign) BOOL hasConnected;
24 | @end
25 |
26 | @implementation RACMulticastConnection
27 |
28 | #pragma mark Lifecycle
29 |
30 | - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
31 | NSCParameterAssert(source != nil);
32 | NSCParameterAssert(subject != nil);
33 |
34 | self = [super init];
35 | if (self == nil) return nil;
36 |
37 | _sourceSignal = source;
38 | _signal = subject;
39 |
40 | return self;
41 | }
42 |
43 | #pragma mark Connecting
44 |
45 | - (RACDisposable *)connect {
46 | BOOL shouldConnect = NO;
47 | @synchronized(self) {
48 | if (!self.hasConnected) {
49 | shouldConnect = YES;
50 | self.hasConnected = YES;
51 | }
52 | }
53 |
54 | if (shouldConnect) {
55 | self.disposable = [self.sourceSignal subscribe:_signal];
56 | }
57 |
58 | return self.disposable;
59 | }
60 |
61 | - (RACSignal *)autoconnect {
62 | return [[RACSignal createSignal:^(id subscriber) {
63 | RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
64 | [self connect];
65 |
66 | return [RACDisposable disposableWithBlock:^{
67 | [subscriptionDisposable dispose];
68 |
69 | @synchronized(self.signal.subscribers) {
70 | if (self.signal.subscribers.count < 1) {
71 | [self.disposable dispose];
72 | }
73 | }
74 | }];
75 | }] setNameWithFormat:@"[%@] -autoconnect", self.signal.name];
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEagerSequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACEagerSequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 02/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACEagerSequence.h"
10 | #import "NSObject+RACDescription.h"
11 | #import "RACArraySequence.h"
12 |
13 | @implementation RACEagerSequence
14 |
15 | #pragma mark RACStream
16 |
17 | + (instancetype)return:(id)value {
18 | return [[self sequenceWithArray:@[ value ] offset:0] setNameWithFormat:@"+return: %@", [value rac_description]];
19 | }
20 |
21 | - (instancetype)bind:(RACStreamBindBlock (^)(void))block {
22 | NSCParameterAssert(block != nil);
23 | RACStreamBindBlock bindBlock = block();
24 | NSArray *currentArray = self.array;
25 | NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:currentArray.count];
26 |
27 | for (id value in currentArray) {
28 | BOOL stop = NO;
29 | RACSequence *boundValue = (id)bindBlock(value, &stop);
30 | if (boundValue == nil) break;
31 |
32 | for (id x in boundValue) {
33 | [resultArray addObject:x];
34 | }
35 |
36 | if (stop) break;
37 | }
38 |
39 | return [[self.class sequenceWithArray:resultArray offset:0] setNameWithFormat:@"[%@] -bind:", self.name];
40 | }
41 |
42 | - (instancetype)concat:(RACSequence *)sequence {
43 | NSCParameterAssert(sequence != nil);
44 | NSCParameterAssert([sequence isKindOfClass:RACSequence.class]);
45 |
46 | NSArray *array = [self.array arrayByAddingObjectsFromArray:sequence.array];
47 | return [[self.class sequenceWithArray:array offset:0] setNameWithFormat:@"[%@] -concat: %@", self.name, sequence];
48 | }
49 |
50 | #pragma mark Extended methods
51 |
52 | - (RACSequence *)eagerSequence {
53 | return self;
54 | }
55 |
56 | - (RACSequence *)lazySequence {
57 | return [RACArraySequence sequenceWithArray:self.array offset:0];
58 | }
59 |
60 | - (id)foldRightWithStart:(id)start combine:(id (^)(id, RACSequence *rest))combine {
61 | return [super foldRightWithStart:start combine:^(id first, RACSequence *rest) {
62 | return combine(first, rest.eagerSequence);
63 | }];
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSObjectRACSelectorSignal.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObjectRACSelectorSignal.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/18/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACTestObject.h"
10 | #import "RACSubclassObject.h"
11 | #import "NSObject+RACSelectorSignal.h"
12 | #import "RACSignal.h"
13 |
14 | SpecBegin(NSObjectRACSelectorSignal)
15 |
16 | describe(@"with an instance method", ^{
17 | it(@"should send the argument for each invocation", ^{
18 | RACSubclassObject *object = [[RACSubclassObject alloc] init];
19 | __block id value;
20 | [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(id x) {
21 | value = x;
22 | }];
23 |
24 | [object lifeIsGood:@42];
25 |
26 | expect(value).to.equal(@42);
27 | });
28 |
29 | it(@"shouldn't swizzle an existing method", ^{
30 | RACTestObject *object = [[RACTestObject alloc] init];
31 | #ifndef NS_BLOCK_ASSERTIONS
32 | expect(^{
33 | [object rac_signalForSelector:@selector(lifeIsGood:)];
34 | }).to.raiseAny();
35 | #else
36 | __block id value;
37 | [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(id x) {
38 | value = x;
39 | }];
40 |
41 | [object lifeIsGood:@42];
42 |
43 | expect(value).to.beNil();
44 | #endif
45 | });
46 | });
47 |
48 | describe(@"with a class method", ^{
49 | it(@"should send the argument for each invocation", ^{
50 | __block id value;
51 | [[RACSubclassObject rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(id x) {
52 | value = x;
53 | }];
54 |
55 | [RACSubclassObject lifeIsGood:@42];
56 |
57 | expect(value).to.equal(@42);
58 | });
59 |
60 | it(@"shouldn't swizzle an existing method", ^{
61 | #ifndef NS_BLOCK_ASSERTIONS
62 | expect(^{
63 | [RACTestObject rac_signalForSelector:@selector(lifeIsGood:)];
64 | }).to.raiseAny();
65 | #else
66 | __block id value;
67 | [[RACTestObject rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(id x) {
68 | value = x;
69 | }];
70 |
71 | [RACTestObject lifeIsGood:@42];
72 |
73 | expect(value).to.beNil();
74 | #endif
75 | });
76 | });
77 |
78 | SpecEnd
79 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarButtonItem+RACCommandSupport.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Kyle LeNeau on 3/27/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "UIBarButtonItem+RACCommandSupport.h"
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 | #import
17 |
18 | static void * UIControlRACCommandKey = &UIControlRACCommandKey;
19 | static void * UIControlRACCommandSignalKey = &UIControlRACCommandSignalKey;
20 |
21 | @implementation UIBarButtonItem (RACCommandSupport)
22 |
23 | - (RACCommand *)rac_command {
24 | return objc_getAssociatedObject(self, UIControlRACCommandKey);
25 | }
26 |
27 | - (void)setRac_command:(RACCommand *)command {
28 | objc_setAssociatedObject(self, UIControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
29 |
30 | if (command == nil) return;
31 |
32 | // Check for stored signal in order to remove it and add a new one
33 | RACDisposable *existingSignal = objc_getAssociatedObject(self, UIControlRACCommandSignalKey);
34 | [existingSignal dispose];
35 |
36 | RACDisposable *newSignal = [RACAbleWithStart(command, canExecute) toProperty:@keypath(self.enabled) onObject:self];
37 | objc_setAssociatedObject(self, UIControlRACCommandSignalKey, newSignal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
38 |
39 | [self rac_hijackActionAndTargetIfNeeded];
40 | }
41 |
42 | - (void)rac_hijackActionAndTargetIfNeeded {
43 | SEL hijackSelector = @selector(rac_commandPerformAction:);
44 | if (self.target == self && self.action == hijackSelector) return;
45 |
46 | if (self.target != nil) NSLog(@"WARNING: UIBarButtonItem.rac_command hijacks the control's existing target and action.");
47 |
48 | self.target = self;
49 | self.action = hijackSelector;
50 | }
51 |
52 | - (void)rac_commandPerformAction:(id)sender {
53 | [self.rac_command execute:sender];
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACSelectorSignal.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACSelectorSignal.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/18/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACSelectorSignal.h"
10 | #import "RACSubject.h"
11 | #import "NSObject+RACPropertySubscribing.h"
12 | #import "RACDisposable.h"
13 | #import
14 |
15 | static const void *RACObjectSelectorSignals = &RACObjectSelectorSignals;
16 |
17 | @implementation NSObject (RACSelectorSignal)
18 |
19 | static RACSignal *NSObjectRACSignalForSelector(id self, SEL _cmd, SEL selector) {
20 | NSCParameterAssert([NSStringFromSelector(selector) componentsSeparatedByString:@":"].count == 2);
21 |
22 | @synchronized(self) {
23 | NSMutableDictionary *selectorSignals = objc_getAssociatedObject(self, RACObjectSelectorSignals);
24 | if (selectorSignals == nil) {
25 | selectorSignals = [NSMutableDictionary dictionary];
26 | objc_setAssociatedObject(self, RACObjectSelectorSignals, selectorSignals, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
27 | }
28 |
29 | NSString *key = NSStringFromSelector(selector);
30 | RACSubject *subject = selectorSignals[key];
31 | if (subject != nil) return subject;
32 |
33 | subject = [RACSubject subject];
34 | IMP imp = imp_implementationWithBlock(^(id self, id arg) {
35 | [subject sendNext:arg];
36 | });
37 |
38 | BOOL success = class_addMethod(object_getClass(self), selector, imp, "v@:@");
39 | NSCAssert(success, @"%@ is already implemented on %@. %@ will not replace the existing implementation.", NSStringFromSelector(selector), self, NSStringFromSelector(_cmd));
40 | if (!success) return nil;
41 |
42 | selectorSignals[key] = subject;
43 |
44 | [self rac_addDeallocDisposable:[RACDisposable disposableWithBlock:^{
45 | [subject sendCompleted];
46 | }]];
47 |
48 | return subject;
49 | }
50 | }
51 |
52 | - (RACSignal *)rac_signalForSelector:(SEL)selector {
53 | return NSObjectRACSignalForSelector(self, _cmd, selector);
54 | }
55 |
56 | + (RACSignal *)rac_signalForSelector:(SEL)selector {
57 | return NSObjectRACSignalForSelector(self, _cmd, selector);
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/RACExtensions/NSTask+RACSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSTask+RACSupport.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 5/10/12.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | extern NSString * const NSTaskRACSupportErrorDomain;
13 |
14 | // The NSData from the standard output.
15 | extern NSString * const NSTaskRACSupportOutputData;
16 |
17 | // The NSData from the standard error.
18 | extern NSString * const NSTaskRACSupportErrorData;
19 |
20 | // The NSString created from the output data. May be nil if a string couldn't
21 | // be made from the data.
22 | extern NSString * const NSTaskRACSupportOutputString;
23 |
24 | // The NSString created from the error data. May be nil if a string couldn't
25 | // be made from the data.
26 | extern NSString * const NSTaskRACSupportErrorString;
27 |
28 | // An NSArray of the task's arguments.
29 | extern NSString * const NSTaskRACSupportTaskArguments;
30 |
31 | // The task itself.
32 | extern NSString * const NSTaskRACSupportTask;
33 |
34 | extern const NSInteger NSTaskRACSupportNonZeroTerminationStatus;
35 |
36 | @interface NSTask (RACSupport)
37 |
38 | // Returns a signal to the standard output. Does not start the task.
39 | - (RACSignal *)rac_standardOutput;
40 |
41 | // Returns a signal to the standard error. Does not start the task.
42 | - (RACSignal *)rac_standardError;
43 |
44 | // Returns a signal that sends a `RACUnit.defaultUnit` and completes when the
45 | // task completes.
46 | - (RACSignal *)rac_completion;
47 |
48 | // Runs the task asychronously on the main queue. It aggregates all the data
49 | // from standard output and sends it once the task completes, scheduled on the
50 | // given scheduler. If the task exists with a non-zero status, it sends an
51 | // error. The error's userInfo contains objects of the keys
52 | // NSTaskRACSupportOutputData, NSTaskRACSupportErrorData, and NSTaskRACSupportTask.
53 | //
54 | // scheduler - cannot be nil.
55 | - (RACSignal *)rac_runWithScheduler:(RACScheduler *)scheduler;
56 |
57 | // Calls -rac_runWithScheduler: with the immediate scheduler.
58 | - (RACSignal *)rac_run;
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACTupleSequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACTupleSequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-01.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACTupleSequence.h"
10 | #import "RACTuple.h"
11 |
12 | @interface RACTupleSequence ()
13 |
14 | // The array being sequenced, as taken from RACTuple.backingArray.
15 | @property (nonatomic, strong, readonly) NSArray *tupleBackingArray;
16 |
17 | // The index in the array from which the sequence starts.
18 | @property (nonatomic, assign, readonly) NSUInteger offset;
19 |
20 | @end
21 |
22 | @implementation RACTupleSequence
23 |
24 | #pragma mark Lifecycle
25 |
26 | + (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset {
27 | NSCParameterAssert(offset <= backingArray.count);
28 |
29 | if (offset == backingArray.count) return self.empty;
30 |
31 | RACTupleSequence *seq = [[self alloc] init];
32 | seq->_tupleBackingArray = backingArray;
33 | seq->_offset = offset;
34 | return seq;
35 | }
36 |
37 | #pragma mark RACSequence
38 |
39 | - (id)head {
40 | id object = [self.tupleBackingArray objectAtIndex:self.offset];
41 | return (object == RACTupleNil.tupleNil ? NSNull.null : object);
42 | }
43 |
44 | - (RACSequence *)tail {
45 | RACSequence *sequence = [self.class sequenceWithTupleBackingArray:self.tupleBackingArray offset:self.offset + 1];
46 | sequence.name = self.name;
47 | return sequence;
48 | }
49 |
50 | - (NSArray *)array {
51 | NSRange range = NSMakeRange(self.offset, self.tupleBackingArray.count - self.offset);
52 | NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:range.length];
53 |
54 | [self.tupleBackingArray enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] options:0 usingBlock:^(id object, NSUInteger index, BOOL *stop) {
55 | id mappedObject = (object == RACTupleNil.tupleNil ? NSNull.null : object);
56 | [array addObject:mappedObject];
57 | }];
58 |
59 | return array;
60 | }
61 |
62 | #pragma mark NSObject
63 |
64 | - (NSString *)description {
65 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@, tuple = %@ }", self.class, self, self.name, self.tupleBackingArray];
66 | }
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACUnarySequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACUnarySequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-05-01.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACUnarySequence.h"
10 | #import "EXTKeyPathCoding.h"
11 | #import "NSObject+RACDescription.h"
12 |
13 | @interface RACUnarySequence ()
14 |
15 | // The single value stored in this sequence.
16 | @property (nonatomic, strong, readwrite) id head;
17 |
18 | @end
19 |
20 | @implementation RACUnarySequence
21 |
22 | #pragma mark Properties
23 |
24 | @synthesize head = _head;
25 |
26 | #pragma mark Lifecycle
27 |
28 | + (instancetype)return:(id)value {
29 | RACUnarySequence *sequence = [[self alloc] init];
30 | sequence.head = value;
31 | return [sequence setNameWithFormat:@"+return: %@", [value rac_description]];
32 | }
33 |
34 | #pragma mark RACSequence
35 |
36 | - (RACSequence *)tail {
37 | return nil;
38 | }
39 |
40 | - (instancetype)bind:(RACStreamBindBlock (^)(void))block {
41 | RACStreamBindBlock bindBlock = block();
42 | BOOL stop = NO;
43 |
44 | RACSequence *result = (id)[bindBlock(self.head, &stop) setNameWithFormat:@"[%@] -bind:", self.name];
45 | return result ?: self.class.empty;
46 | }
47 |
48 | #pragma mark NSCoding
49 |
50 | - (Class)classForCoder {
51 | // Unary sequences should be encoded as themselves, not array sequences.
52 | return self.class;
53 | }
54 |
55 | - (id)initWithCoder:(NSCoder *)coder {
56 | id value = [coder decodeObjectForKey:@keypath(self.head)];
57 | return [self.class return:value];
58 | }
59 |
60 | - (void)encodeWithCoder:(NSCoder *)coder {
61 | if (self.head != nil) [coder encodeObject:self.head forKey:@keypath(self.head)];
62 | }
63 |
64 | #pragma mark NSObject
65 |
66 | - (NSString *)description {
67 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@, head = %@ }", self.class, self, self.name, [self.head rac_description]];
68 | }
69 |
70 | - (NSUInteger)hash {
71 | return [self.head hash];
72 | }
73 |
74 | - (BOOL)isEqual:(RACUnarySequence *)seq {
75 | if (self == seq) return YES;
76 | if (![seq isKindOfClass:RACUnarySequence.class]) return NO;
77 |
78 | return self.head == seq.head || [(NSObject *)self.head isEqual:seq.head];
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriber.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriber.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/1/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class RACDisposable;
12 |
13 | // Represents any object which can directly receive values from a RACSignal.
14 | //
15 | // You generally shouldn't need to implement this protocol. +[RACSignal
16 | // createSignal:], RACSignal's subscription methods, or RACSubject should work
17 | // for most uses.
18 | //
19 | // Implementors of this protocol may receive messages and values from multiple
20 | // threads simultaneously, and so should be thread-safe. Subscribers will also
21 | // be weakly referenced so implementations must allow that.
22 | @protocol RACSubscriber
23 | @required
24 |
25 | // Send the next value to subscribers.
26 | //
27 | // value - The value to send. This can be `nil`.
28 | - (void)sendNext:(id)value;
29 |
30 | // Send the error to subscribers.
31 | //
32 | // error - The error to send. This can be `nil`.
33 | //
34 | // This terminates the subscription, and invalidates the subscriber (such that
35 | // it cannot subscribe to anything else in the future).
36 | - (void)sendError:(NSError *)error;
37 |
38 | // Send completed to subscribers.
39 | //
40 | // This terminates the subscription, and invalidates the subscriber (such that
41 | // it cannot subscribe to anything else in the future).
42 | - (void)sendCompleted;
43 |
44 | // Sends the subscriber a disposable that represents one of its subscriptions.
45 | //
46 | // A subscriber may receive multiple disposables if it gets subscribed to
47 | // multiple signals; however, any error or completed events must terminate _all_
48 | // subscriptions.
49 | - (void)didSubscribeWithDisposable:(RACDisposable *)disposable;
50 |
51 | @end
52 |
53 | // A simple block-based subscriber.
54 | //
55 | // You shouldn't need to interact with this class directly. Use
56 | // -[RACSignal subscribeNext:error:completed:] instead.
57 | @interface RACSubscriber : NSObject
58 |
59 | // Creates a new subscriber with the given blocks.
60 | + (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa.xcodeproj/xcshareddata/xcschemes/ReactiveCocoa-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACQueueScheduler.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACQueueScheduler.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACQueueScheduler.h"
10 | #import "RACDisposable.h"
11 | #import "RACScheduler+Private.h"
12 | #import
13 |
14 | @interface RACQueueScheduler ()
15 | @property (nonatomic, readonly) dispatch_queue_t queue;
16 | @end
17 |
18 | @implementation RACQueueScheduler
19 |
20 | #pragma mark Lifecycle
21 |
22 | - (void)dealloc {
23 | dispatch_release(_queue);
24 | }
25 |
26 | - (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue {
27 | NSCParameterAssert(targetQueue != NULL);
28 |
29 | _queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL);
30 | if (_queue == nil) return nil;
31 |
32 | dispatch_set_target_queue(_queue, targetQueue);
33 |
34 | return [super initWithName:name];
35 | }
36 |
37 | #pragma mark Current Scheduler
38 |
39 | static void currentSchedulerRelease(void *context) {
40 | CFBridgingRelease(context);
41 | }
42 |
43 | - (void)performAsCurrentScheduler:(void (^)(void))block {
44 | NSCParameterAssert(block != NULL);
45 |
46 | dispatch_queue_set_specific(self.queue, RACSchedulerCurrentSchedulerKey, (void *)CFBridgingRetain(self), currentSchedulerRelease);
47 | block();
48 | dispatch_queue_set_specific(self.queue, RACSchedulerCurrentSchedulerKey, nil, currentSchedulerRelease);
49 | }
50 |
51 | #pragma mark RACScheduler
52 |
53 | - (RACDisposable *)schedule:(void (^)(void))block {
54 | NSCParameterAssert(block != NULL);
55 |
56 | __block volatile uint32_t disposed = 0;
57 |
58 | dispatch_async(self.queue, ^{
59 | if (disposed != 0) return;
60 | [self performAsCurrentScheduler:block];
61 | });
62 |
63 | return [RACDisposable disposableWithBlock:^{
64 | OSAtomicOr32Barrier(1, &disposed);
65 | }];
66 | }
67 |
68 | - (RACDisposable *)after:(dispatch_time_t)when schedule:(void (^)(void))block {
69 | NSCParameterAssert(block != NULL);
70 |
71 | __block volatile uint32_t disposed = 0;
72 |
73 | dispatch_after(when, self.queue, ^{
74 | if (disposed != 0) return;
75 | [self performAsCurrentScheduler:block];
76 | });
77 |
78 | return [RACDisposable disposableWithBlock:^{
79 | OSAtomicOr32Barrier(1, &disposed);
80 | }];
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACSubscriber.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriber.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/1/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubscriber.h"
10 | #import "EXTScope.h"
11 | #import "RACCompoundDisposable.h"
12 |
13 | @interface RACSubscriber ()
14 |
15 | @property (nonatomic, copy, readonly) void (^next)(id value);
16 | @property (nonatomic, copy, readonly) void (^error)(NSError *error);
17 | @property (nonatomic, copy, readonly) void (^completed)(void);
18 | @property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
19 |
20 | // This property should only be used while synchronized on self.
21 | @property (nonatomic, assign) BOOL disposed;
22 |
23 | @end
24 |
25 | @implementation RACSubscriber
26 |
27 | #pragma mark Lifecycle
28 |
29 | + (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
30 | RACSubscriber *subscriber = [[self alloc] init];
31 |
32 | subscriber->_next = [next copy];
33 | subscriber->_error = [error copy];
34 | subscriber->_completed = [completed copy];
35 |
36 | return subscriber;
37 | }
38 |
39 | - (id)init {
40 | self = [super init];
41 | if (self == nil) return nil;
42 |
43 | @weakify(self);
44 |
45 | RACDisposable *selfDisposable = [RACDisposable disposableWithBlock:^{
46 | @strongify(self);
47 |
48 | @synchronized (self) {
49 | self.disposed = YES;
50 | }
51 | }];
52 |
53 | _disposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ selfDisposable ]];
54 |
55 | return self;
56 | }
57 |
58 | - (void)dealloc {
59 | [self.disposable dispose];
60 | }
61 |
62 | #pragma mark RACSubscriber
63 |
64 | - (void)sendNext:(id)value {
65 | if (self.next == NULL) return;
66 |
67 | @synchronized (self) {
68 | if (self.disposed) return;
69 | self.next(value);
70 | }
71 | }
72 |
73 | - (void)sendError:(NSError *)e {
74 | @synchronized (self) {
75 | if (self.disposed) return;
76 |
77 | [self.disposable dispose];
78 | if (self.error != NULL) self.error(e);
79 | }
80 | }
81 |
82 | - (void)sendCompleted {
83 | @synchronized (self) {
84 | if (self.disposed) return;
85 |
86 | [self.disposable dispose];
87 | if (self.completed != NULL) self.completed();
88 | }
89 | }
90 |
91 | - (void)didSubscribeWithDisposable:(RACDisposable *)d {
92 | if (d != nil) [self.disposable addDisposable:d];
93 | }
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACCompoundDisposableSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACCompoundDisposableSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACCompoundDisposable.h"
10 |
11 | SpecBegin(RACCompoundDisposable)
12 |
13 | it(@"should dispose of all its contained disposables", ^{
14 | __block BOOL d1Disposed = NO;
15 | RACDisposable *d1 = [RACDisposable disposableWithBlock:^{
16 | d1Disposed = YES;
17 | }];
18 |
19 | __block BOOL d2Disposed = NO;
20 | RACDisposable *d2 = [RACDisposable disposableWithBlock:^{
21 | d2Disposed = YES;
22 | }];
23 |
24 | __block BOOL d3Disposed = NO;
25 | RACDisposable *d3 = [RACDisposable disposableWithBlock:^{
26 | d3Disposed = YES;
27 | }];
28 |
29 | RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ d1, d2 ]];
30 | [disposable addDisposable:d3];
31 | expect(d1Disposed).to.beFalsy();
32 | expect(d2Disposed).to.beFalsy();
33 | expect(d3Disposed).to.beFalsy();
34 |
35 | [disposable dispose];
36 | expect(d1Disposed).to.beTruthy();
37 | expect(d2Disposed).to.beTruthy();
38 | expect(d3Disposed).to.beTruthy();
39 | });
40 |
41 | it(@"should dispose of any added disposables immediately if it's already been disposed", ^{
42 | RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
43 | [disposable dispose];
44 |
45 | __block BOOL disposed = NO;
46 | RACDisposable *d = [RACDisposable disposableWithBlock:^{
47 | disposed = YES;
48 | }];
49 |
50 | expect(disposed).to.beFalsy();
51 | [disposable addDisposable:d];
52 | expect(disposed).to.beTruthy();
53 | });
54 |
55 | it(@"should work when initialized with -init", ^{
56 | RACCompoundDisposable *disposable = [[RACCompoundDisposable alloc] init];
57 |
58 | __block BOOL disposed = NO;
59 | RACDisposable *d = [RACDisposable disposableWithBlock:^{
60 | disposed = YES;
61 | }];
62 |
63 | [disposable addDisposable:d];
64 | expect(disposed).to.beFalsy();
65 |
66 | [disposable dispose];
67 | expect(disposed).to.beTruthy();
68 | });
69 |
70 | it(@"should allow disposables to be removed", ^{
71 | RACCompoundDisposable *disposable = [[RACCompoundDisposable alloc] init];
72 |
73 | __block BOOL disposed = NO;
74 | RACDisposable *d = [RACDisposable disposableWithBlock:^{
75 | disposed = YES;
76 | }];
77 |
78 | [disposable addDisposable:d];
79 | [disposable removeDisposable:d];
80 |
81 | [disposable dispose];
82 | expect(disposed).to.beFalsy();
83 | });
84 |
85 | SpecEnd
86 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/ReactiveCocoa.h:
--------------------------------------------------------------------------------
1 | //
2 | // ReactiveCocoa.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/5/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 | #import
17 | #import
18 | #import
19 | #import
20 | #import
21 | #import
22 | #import
23 | #import
24 | #import
25 | #import
26 | #import
27 | #import
28 | #import
29 | #import
30 | #import
31 | #import
32 | #import
33 | #import
34 | #import
35 | #import
36 | #import
37 | #import
38 | #import
39 | #import
40 | #import
41 | #import
42 |
43 | #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
44 | #import
45 | #import
46 | #import
47 | #import
48 | #import
49 | #import
50 | #elif TARGET_OS_MAC
51 | #import
52 | #import
53 | #import
54 | #import
55 | #import
56 | #endif
57 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACBinding.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACBinding.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 01/01/2013.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACBinding.h"
10 | #import "RACDisposable.h"
11 | #import "RACTuple.h"
12 | #import "EXTScope.h"
13 |
14 | @interface RACBinding ()
15 |
16 | // The signal exposed to callers. The property will behave like this signal
17 | // towards it's subscribers.
18 | @property (nonatomic, readonly, strong) RACSignal *exposedSignal;
19 |
20 | // The subscriber exposed to callers. The property will behave like this
21 | // subscriber towards the signals it's subscribed to.
22 | @property (nonatomic, readonly, strong) id exposedSubscriber;
23 |
24 | @end
25 |
26 | @implementation RACBinding
27 |
28 | #pragma mark RACSignal
29 |
30 | - (RACDisposable *)subscribe:(id)subscriber {
31 | return [self.exposedSignal subscribe:subscriber];
32 | }
33 |
34 | #pragma mark
35 |
36 | - (void)sendNext:(id)value {
37 | [self.exposedSubscriber sendNext:value];
38 | }
39 |
40 | - (void)sendError:(NSError *)error {
41 | [self.exposedSubscriber sendError:error];
42 | }
43 |
44 | - (void)sendCompleted {
45 | [self.exposedSubscriber sendCompleted];
46 | }
47 |
48 | - (void)didSubscribeWithDisposable:(RACDisposable *)disposable {
49 | [self.exposedSubscriber didSubscribeWithDisposable:disposable];
50 | }
51 |
52 | #pragma mark API
53 |
54 | - (instancetype)initWithSignal:(RACSignal *)signal subscriber:(id)subscriber {
55 | self = [super init];
56 | if (self == nil) return nil;
57 |
58 | @weakify(self);
59 | _exposedSignal = [RACSignal createSignal:^(id subscriber) {
60 | __block BOOL isFirstNext = YES;
61 | return [signal subscribeNext:^(RACTuple *x) {
62 | @strongify(self);
63 | if (isFirstNext || ![x.second isEqual:self]) {
64 | isFirstNext = NO;
65 | [subscriber sendNext:x.first];
66 | }
67 | }];
68 | }];
69 | _exposedSubscriber = [RACSubscriber subscriberWithNext:^(id x) {
70 | @strongify(self);
71 | [subscriber sendNext:[RACTuple tupleWithObjects:x ?: RACTupleNil.tupleNil, self ?: RACTupleNil.tupleNil, nil]];
72 | } error:nil completed:nil];
73 |
74 | return self;
75 | }
76 |
77 | - (RACDisposable *)bindTo:(RACBinding *)binding {
78 | RACDisposable *bindingDisposable = [binding subscribe:self];
79 | RACDisposable *selfDisposable = [[self skip:1] subscribe:binding];
80 | return [RACDisposable disposableWithBlock:^{
81 | [bindingDisposable dispose];
82 | [selfDisposable dispose];
83 | }];
84 | }
85 |
86 | @end
87 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACDelegateProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACDelegateProxy.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/19/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACDelegateProxy.h"
10 | #import "RACObjCRuntime.h"
11 | #import "RACEventTrampoline.h"
12 |
13 | @interface RACDelegateProxy ()
14 |
15 | @property (nonatomic, strong) Protocol *protocol;
16 | @property (nonatomic, weak) NSObject *delegator;
17 | @property (nonatomic, readonly, strong) NSMutableSet *trampolines;
18 |
19 | - (BOOL)trampolinesRespondToSelector:(SEL)aSelector;
20 |
21 | @end
22 |
23 | @implementation RACDelegateProxy
24 |
25 | + (instancetype)proxyWithProtocol:(Protocol *)protocol andDelegator:(NSObject *)delegator {
26 | if (![self conformsToProtocol:protocol]) {
27 | class_addProtocol(self.class, protocol);
28 | }
29 |
30 | RACDelegateProxy *proxy = [[self alloc] init];
31 | proxy.protocol = protocol;
32 | proxy.delegator = delegator;
33 | return proxy;
34 | }
35 |
36 | - (instancetype)init {
37 | self = [super init];
38 | if (self == nil) return nil;
39 |
40 | _trampolines = [[NSMutableSet alloc] init];
41 |
42 | return self;
43 | }
44 |
45 | - (BOOL)respondsToSelector:(SEL)selector {
46 | // Add the original delegate to the autorelease pool, so it doesn't get
47 | // deallocated between this method call and -forwardInvocation:.
48 | __autoreleasing id actual = self.actualDelegate;
49 | if ([actual respondsToSelector:selector] || [self trampolinesRespondToSelector:selector]) return YES;
50 |
51 | return [super respondsToSelector:selector];
52 | }
53 |
54 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
55 | return [NSMethodSignature signatureWithObjCTypes:[RACObjCRuntime getMethodTypesForMethod:selector inProtocol:self.protocol]];
56 | }
57 |
58 | - (void)forwardInvocation:(NSInvocation *)invocation {
59 | SEL selector = invocation.selector;
60 | for (RACEventTrampoline *trampoline in self.trampolines) {
61 | [trampoline didGetDelegateEvent:selector sender:self.delegator];
62 | }
63 |
64 | id actual = self.actualDelegate;
65 | if ([actual respondsToSelector:selector]) {
66 | [invocation invokeWithTarget:actual];
67 | }
68 | }
69 |
70 | - (void)addTrampoline:(RACEventTrampoline *)trampoline {
71 | trampoline.proxy = self;
72 | [self.trampolines addObject:trampoline];
73 | }
74 |
75 | - (BOOL)trampolinesRespondToSelector:(SEL)selector {
76 | for (RACEventTrampoline *trampoline in self.trampolines) {
77 | if (trampoline.delegateMethod == selector) {
78 | return YES;
79 | }
80 | }
81 |
82 | return NO;
83 | }
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACEventSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACEventSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-01-07.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACEvent.h"
10 |
11 | SpecBegin(RACEvent)
12 |
13 | it(@"should return the singleton completed event", ^{
14 | RACEvent *event = RACEvent.completedEvent;
15 | expect(event).notTo.beNil();
16 |
17 | expect(event).to.beIdenticalTo(RACEvent.completedEvent);
18 | expect([event copy]).to.beIdenticalTo(event);
19 |
20 | expect(event.eventType).to.equal(RACEventTypeCompleted);
21 | expect(event.finished).to.beTruthy();
22 | expect(event.error).to.beNil();
23 | expect(event.value).to.beNil();
24 | });
25 |
26 | it(@"should return an error event", ^{
27 | NSError *error = [NSError errorWithDomain:@"foo" code:1 userInfo:nil];
28 | RACEvent *event = [RACEvent eventWithError:error];
29 | expect(event).notTo.beNil();
30 |
31 | expect(event).to.equal([RACEvent eventWithError:error]);
32 | expect([event copy]).to.equal(event);
33 |
34 | expect(event.eventType).to.equal(RACEventTypeError);
35 | expect(event.finished).to.beTruthy();
36 | expect(event.error).to.equal(error);
37 | expect(event.value).to.beNil();
38 | });
39 |
40 | it(@"should return an error event with a nil error", ^{
41 | RACEvent *event = [RACEvent eventWithError:nil];
42 | expect(event).notTo.beNil();
43 |
44 | expect(event).to.equal([RACEvent eventWithError:nil]);
45 | expect([event copy]).to.equal(event);
46 |
47 | expect(event.eventType).to.equal(RACEventTypeError);
48 | expect(event.finished).to.beTruthy();
49 | expect(event.error).to.beNil();
50 | expect(event.value).to.beNil();
51 | });
52 |
53 | it(@"should return a next event", ^{
54 | NSString *value = @"foo";
55 | RACEvent *event = [RACEvent eventWithValue:value];
56 | expect(event).notTo.beNil();
57 |
58 | expect(event).to.equal([RACEvent eventWithValue:value]);
59 | expect([event copy]).to.equal(event);
60 |
61 | expect(event.eventType).to.equal(RACEventTypeNext);
62 | expect(event.finished).to.beFalsy();
63 | expect(event.error).to.beNil();
64 | expect(event.value).to.equal(value);
65 | });
66 |
67 | it(@"should return a next event with a nil value", ^{
68 | RACEvent *event = [RACEvent eventWithValue:nil];
69 | expect(event).notTo.beNil();
70 |
71 | expect(event).to.equal([RACEvent eventWithValue:nil]);
72 | expect([event copy]).to.equal(event);
73 |
74 | expect(event.eventType).to.equal(RACEventTypeNext);
75 | expect(event.finished).to.beFalsy();
76 | expect(event.error).to.beNil();
77 | expect(event.value).to.beNil();
78 | });
79 |
80 | SpecEnd
81 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACObservablePropertySubject.h:
--------------------------------------------------------------------------------
1 | //
2 | // RACObservablePropertySubject.h
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 27/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACPropertySubject.h"
10 | #import "EXTKeyPathCoding.h"
11 | #import "metamacros.h"
12 |
13 | // Convenience macro for creating bindings and binding them.
14 | //
15 | // If given just one argument, it's assumed to be a keypath or property on self.
16 | // If given two, the first argument is the object to which the keypath is
17 | // relative and the second is the keypath.
18 | //
19 | // If RACBind() is used as an lvalue (an assignee), the named property is bound
20 | // to the RACBinding provided on the right-hand side of the assignment. The
21 | // binding property's value is set to the value of the property being bound to,
22 | // then any changes to one property will be reflected on the other.
23 | //
24 | // If RACBind() is used as an rvalue, a RACBinding is returned.
25 | //
26 | // Examples:
27 | // RACBinding *binding = RACBind(self.property);
28 | // RACBind(self.property) = RACBind(otherObject, property);
29 | #define RACBind(...) metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(_RACBindObject(self, __VA_ARGS__))(_RACBindObject(__VA_ARGS__))
30 |
31 | // Do not use this directly. Use the RACBind macro above.
32 | #define _RACBindObject(OBJ, KEYPATH) [RACObservablePropertySubject propertyWithTarget:OBJ keyPath:@keypath(OBJ, KEYPATH)][ @"binding" ]
33 |
34 | // A RACPropertySubject wrapper for KVO compliant key paths.
35 | //
36 | // New values of `keyPath` will be sent to the wrapper's subscribers and it's
37 | // bindings' subscribers. `keyPath` will be updated with values sent to the
38 | // wrapper or it's bindings. Subscribers of the wrapper or it's bindings will be
39 | // sent the current value of `keyPath`.
40 | //
41 | // Note: RACObservablePropertySubject is not thread-safe and should not observe
42 | // a property, or be bound to a RACProperty, whose value can be changed from
43 | // multiple threads at the same time.
44 | @interface RACObservablePropertySubject : RACPropertySubject
45 |
46 | // Returns a new RACPropertySubject wrapper for `keyPath` on `target` with a
47 | // starting value equal to the value of `keyPath` on `target`.
48 | + (instancetype)propertyWithTarget:(id)target keyPath:(NSString *)keyPath;
49 |
50 | @end
51 |
52 | // Methods needed for the convenience macro. Do not call explicitly.
53 | @interface RACObservablePropertySubject (RACBind)
54 |
55 | - (id)objectForKeyedSubscript:(id)key;
56 | - (void)setObject:(id)obj forKeyedSubscript:(id)key;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/NSNotificationCenterRACSupportSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNotificationCenterRACSupportSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-12-07.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "NSNotificationCenter+RACSupport.h"
10 |
11 | static NSString * const TestNotification = @"TestNotification";
12 |
13 | SpecBegin(NSNotificationCenterRACSupport)
14 |
15 | __block NSNotificationCenter *notificationCenter;
16 |
17 | beforeEach(^{
18 | // The compiler gets confused and thinks you might be messaging
19 | // NSDistributedNotificationCenter otherwise. Wtf?
20 | notificationCenter = NSNotificationCenter.defaultCenter;
21 | });
22 |
23 | it(@"should send the notification when posted by any object", ^{
24 | RACSignal *signal = [notificationCenter rac_addObserverForName:TestNotification object:nil];
25 |
26 | __block NSUInteger count = 0;
27 | [signal subscribeNext:^(NSNotification *notification) {
28 | ++count;
29 |
30 | expect(notification).to.beKindOf(NSNotification.class);
31 | expect(notification.name).to.equal(TestNotification);
32 | }];
33 |
34 | expect(count).to.equal(0);
35 |
36 | [notificationCenter postNotificationName:TestNotification object:nil];
37 | expect(count).to.equal(1);
38 |
39 | [notificationCenter postNotificationName:TestNotification object:self];
40 | expect(count).to.equal(2);
41 | });
42 |
43 | it(@"should send the notification when posted by a specific object", ^{
44 | RACSignal *signal = [notificationCenter rac_addObserverForName:TestNotification object:self];
45 |
46 | __block NSUInteger count = 0;
47 | [signal subscribeNext:^(NSNotification *notification) {
48 | ++count;
49 |
50 | expect(notification).to.beKindOf(NSNotification.class);
51 | expect(notification.name).to.equal(TestNotification);
52 | expect(notification.object).to.equal(self);
53 | }];
54 |
55 | expect(count).to.equal(0);
56 |
57 | [notificationCenter postNotificationName:TestNotification object:nil];
58 | expect(count).to.equal(0);
59 |
60 | [notificationCenter postNotificationName:TestNotification object:self];
61 | expect(count).to.equal(1);
62 | });
63 |
64 | it(@"shouldn't strongly capture the notification object", ^{
65 | RACSignal *signal __attribute__((objc_precise_lifetime));
66 | __block BOOL dealloced = NO;
67 | @autoreleasepool {
68 | NSObject *notificationObject = [[NSObject alloc] init];
69 | [notificationObject rac_addDeallocDisposable:[RACDisposable disposableWithBlock:^{
70 | dealloced = YES;
71 | }]];
72 | signal = [notificationCenter rac_addObserverForName:TestNotification object:notificationObject];
73 | }
74 |
75 | expect(dealloced).to.beTruthy();
76 | });
77 |
78 | SpecEnd
79 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACKVOTrampoline.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACKVOTrampoline.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 1/15/13.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACKVOTrampoline.h"
10 | #import "NSObject+RACKVOWrapper.h"
11 | #import "NSObject+RACKVOWrapperPrivate.h"
12 |
13 | static void *RACKVOWrapperContext = &RACKVOWrapperContext;
14 |
15 | @interface RACKVOTrampoline ()
16 |
17 | // The keypath which the trampoline is observing.
18 | @property (nonatomic, readonly, copy) NSString *keyPath;
19 |
20 | // These properties should only be manipulated while synchronized on the
21 | // receiver.
22 | @property (nonatomic, readonly, copy) RACKVOBlock block;
23 | @property (nonatomic, readonly, unsafe_unretained) NSObject *target;
24 | @property (nonatomic, readonly, unsafe_unretained) NSObject *observer;
25 |
26 | @end
27 |
28 | @implementation RACKVOTrampoline
29 |
30 | #pragma mark Lifecycle
31 |
32 | - (id)initWithTarget:(NSObject *)target observer:(NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
33 | NSCParameterAssert(target != nil);
34 | NSCParameterAssert(keyPath != nil);
35 | NSCParameterAssert(block != nil);
36 |
37 | self = [super init];
38 | if (self == nil) return nil;
39 |
40 | _keyPath = [keyPath copy];
41 |
42 | _block = [block copy];
43 | _target = target;
44 | _observer = observer;
45 |
46 | [self.target addObserver:self forKeyPath:self.keyPath options:options context:&RACKVOWrapperContext];
47 | [self.target rac_addKVOTrampoline:self];
48 | [self.observer rac_addKVOTrampoline:self];
49 |
50 | return self;
51 | }
52 |
53 | - (void)dealloc {
54 | [self stopObserving];
55 | }
56 |
57 | #pragma mark Observation
58 |
59 | - (void)stopObserving {
60 | NSObject *target;
61 | NSObject *observer;
62 |
63 | @synchronized (self) {
64 | _block = nil;
65 |
66 | target = self.target;
67 | observer = self.observer;
68 |
69 | _target = nil;
70 | _observer = nil;
71 | }
72 |
73 | [target rac_removeKVOTrampoline:self];
74 | [observer rac_removeKVOTrampoline:self];
75 |
76 | [target removeObserver:self forKeyPath:self.keyPath context:&RACKVOWrapperContext];
77 | }
78 |
79 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
80 | if (context != &RACKVOWrapperContext) {
81 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
82 | return;
83 | }
84 |
85 | RACKVOBlock block;
86 | id observer;
87 | id target;
88 |
89 | @synchronized (self) {
90 | block = self.block;
91 | observer = self.observer;
92 | target = self.target;
93 | }
94 |
95 | if (block == nil) return;
96 |
97 | block(target, observer, change);
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/Documentation/DifferencesFromRx.md:
--------------------------------------------------------------------------------
1 | # Differences from Rx
2 |
3 | ReactiveCocoa (RAC) is significantly inspired by .NET's [Reactive
4 | Extensions](http://msdn.microsoft.com/en-us/data/gg577609.aspx) (Rx), but it is not
5 | a direct port. Some concepts or interfaces presented in RAC may be initially
6 | confusing to a developer already familiar with Rx, but it's usually possible to
7 | express the same algorithms.
8 |
9 | Some of the differences, like the naming of methods and classes, are meant to
10 | keep RAC in line with existing Cocoa conventions. Other differences are intended
11 | as improvements over Rx, or may be inspired by other functional reactive
12 | programming paradigms (like the [Elm programming
13 | language](http://elm-lang.org)).
14 |
15 | Here, we'll attempt to document the high-level differences between RAC and Rx.
16 |
17 | ## Interfaces
18 |
19 | RAC does not offer protocols that correspond to the `IEnumerable` and
20 | `IObservable` interfaces in .NET. Instead, the functionality is covered by three
21 | main classes:
22 |
23 | * **[RACStream](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoaFramework/ReactiveCocoa/RACStream.h)**
24 | is an abstract class that implements stream operations using a few basic
25 | primitives. The equivalents to generic LINQ operators can generally be found
26 | on this class.
27 | * **[RACSignal](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoaFramework/ReactiveCocoa/RACSignal.h)**
28 | is a concrete subclass of `RACStream` that implements a _push-driven_ stream,
29 | much like `IObservable`. Time-based operators, or methods dealing with the
30 | `completed` and `error` events, can be found on this class or in the
31 | [RACSignal+Operations](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoaFramework/ReactiveCocoa/RACSignal%2BOperations.h)
32 | category upon it.
33 | * **[RACSequence](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoaFramework/ReactiveCocoa/RACSequence.h)**
34 | is a concrete subclass of `RACStream` that implements a _pull-driven_ stream,
35 | much like `IEnumerable`.
36 |
37 | ## Names of Stream Operations
38 |
39 | RAC generally uses LINQ-style naming for its stream methods. Most of the
40 | exceptions are inspired by significantly better alternatives in Haskell or Elm.
41 |
42 | Notable differences include:
43 |
44 | * `-map:` instead of `Select`
45 | * `-filter:` instead of `Where`
46 | * `-flatten` instead of `Merge`
47 | * `-flattenMap:` instead of `SelectMany`
48 |
49 | LINQ operators that go by different names in RAC (but behave more or less
50 | equivalently) will be referenced from method documentation, like so:
51 |
52 | ```objc
53 | // Maps `block` across the values in the receiver.
54 | //
55 | // This corresponds to the `Select` method in Rx.
56 | //
57 | // Returns a new stream with the mapped values.
58 | - (instancetype)map:(id (^)(id value))block;
59 | ```
60 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACCompoundDisposable.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACCompoundDisposable.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 11/30/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACCompoundDisposable.h"
10 | #import "EXTScope.h"
11 | #import
12 |
13 | @interface RACCompoundDisposable () {
14 | // Used for synchronization.
15 | OSSpinLock _spinLock;
16 | }
17 |
18 | // These properties should only be accessed while _spinLock is held.
19 | @property (nonatomic, strong) NSMutableArray *disposables;
20 | @property (nonatomic, assign, getter = isDisposed) BOOL disposed;
21 |
22 | @end
23 |
24 | @implementation RACCompoundDisposable
25 |
26 | #pragma mark Initializers
27 |
28 | + (instancetype)compoundDisposable {
29 | return [[self alloc] initWithDisposables:nil];
30 | }
31 |
32 | + (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables {
33 | return [[self alloc] initWithDisposables:disposables];
34 | }
35 |
36 | - (id)init {
37 | self = [super init];
38 | if (self == nil) return nil;
39 |
40 | _disposables = [NSMutableArray array];
41 |
42 | return self;
43 | }
44 |
45 | - (id)initWithDisposables:(NSArray *)disposables {
46 | self = [self init];
47 | if (self == nil) return nil;
48 |
49 | if (disposables != nil) [self.disposables addObjectsFromArray:disposables];
50 |
51 | return self;
52 | }
53 |
54 | #pragma mark Compound
55 |
56 | - (void)addDisposable:(RACDisposable *)disposable {
57 | NSCParameterAssert(disposable != nil);
58 | NSCParameterAssert(disposable != self);
59 |
60 | BOOL shouldDispose = NO;
61 |
62 | {
63 | OSSpinLockLock(&_spinLock);
64 |
65 | // Ensures exception safety.
66 | @onExit {
67 | OSSpinLockUnlock(&_spinLock);
68 | };
69 |
70 | if (self.disposed) {
71 | shouldDispose = YES;
72 | } else {
73 | [self.disposables addObject:disposable];
74 | }
75 | }
76 |
77 | // Performed outside of the lock in case the compound disposable is used
78 | // recursively.
79 | if (shouldDispose) [disposable dispose];
80 | }
81 |
82 | - (void)removeDisposable:(RACDisposable *)disposable {
83 | if (disposable == nil) return;
84 |
85 | OSSpinLockLock(&_spinLock);
86 |
87 | // Ensures exception safety.
88 | @onExit {
89 | OSSpinLockUnlock(&_spinLock);
90 | };
91 |
92 | [self.disposables removeObjectIdenticalTo:disposable];
93 | }
94 |
95 | #pragma mark RACDisposable
96 |
97 | - (void)dispose {
98 | NSArray *disposables = nil;
99 |
100 | {
101 | OSSpinLockLock(&_spinLock);
102 |
103 | // Ensures exception safety.
104 | @onExit {
105 | OSSpinLockUnlock(&_spinLock);
106 | };
107 |
108 | self.disposed = YES;
109 |
110 | disposables = self.disposables;
111 | self.disposables = nil;
112 | }
113 |
114 | // Performed outside of the lock in case the compound disposable is used
115 | // recursively.
116 | [disposables makeObjectsPerformSelector:@selector(dispose)];
117 | }
118 |
119 | @end
120 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEvent.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACEvent.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2013-01-07.
6 | // Copyright (c) 2013 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACEvent.h"
10 |
11 | @interface RACEvent ()
12 |
13 | // An object associated with this event. This will be used for the error and
14 | // value properties.
15 | @property (nonatomic, strong, readonly) id object;
16 |
17 | // Initializes the receiver with the given type and object.
18 | - (id)initWithEventType:(RACEventType)type object:(id)object;
19 |
20 | @end
21 |
22 | @implementation RACEvent
23 |
24 | #pragma mark Properties
25 |
26 | - (BOOL)isFinished {
27 | return self.eventType == RACEventTypeCompleted || self.eventType == RACEventTypeError;
28 | }
29 |
30 | - (NSError *)error {
31 | return (self.eventType == RACEventTypeError ? self.object : nil);
32 | }
33 |
34 | - (id)value {
35 | return (self.eventType == RACEventTypeNext ? self.object : nil);
36 | }
37 |
38 | #pragma mark Lifecycle
39 |
40 | + (instancetype)completedEvent {
41 | static dispatch_once_t pred;
42 | static id singleton;
43 |
44 | dispatch_once(&pred, ^{
45 | singleton = [[self alloc] initWithEventType:RACEventTypeCompleted object:nil];
46 | });
47 |
48 | return singleton;
49 | }
50 |
51 | + (instancetype)eventWithError:(NSError *)error {
52 | return [[self alloc] initWithEventType:RACEventTypeError object:error];
53 | }
54 |
55 | + (instancetype)eventWithValue:(id)value {
56 | return [[self alloc] initWithEventType:RACEventTypeNext object:value];
57 | }
58 |
59 | - (id)initWithEventType:(RACEventType)type object:(id)object {
60 | self = [super init];
61 | if (self == nil) return nil;
62 |
63 | _eventType = type;
64 | _object = object;
65 |
66 | return self;
67 | }
68 |
69 | #pragma mark NSCopying
70 |
71 | - (id)copyWithZone:(NSZone *)zone {
72 | return self;
73 | }
74 |
75 | #pragma mark NSObject
76 |
77 | - (NSString *)description {
78 | NSString *eventDescription = nil;
79 |
80 | switch (self.eventType) {
81 | case RACEventTypeCompleted:
82 | eventDescription = @"completed";
83 | break;
84 |
85 | case RACEventTypeError:
86 | eventDescription = [NSString stringWithFormat:@"error = %@", self.object];
87 | break;
88 |
89 | case RACEventTypeNext:
90 | eventDescription = [NSString stringWithFormat:@"next = %@", self.object];
91 | break;
92 |
93 | default:
94 | NSCAssert(NO, @"Unrecognized event type: %i", (int)self.eventType);
95 | }
96 |
97 | return [NSString stringWithFormat:@"<%@: %p>{ %@ }", self.class, self, eventDescription];
98 | }
99 |
100 | - (NSUInteger)hash {
101 | return self.eventType ^ [self.object hash];
102 | }
103 |
104 | - (BOOL)isEqual:(id)event {
105 | if (event == self) return YES;
106 | if (![event isKindOfClass:RACEvent.class]) return NO;
107 | if (self.eventType != [event eventType]) return NO;
108 |
109 | // Catches the nil case too.
110 | return self.object == [event object] || [self.object isEqual:[event object]];
111 | }
112 |
113 | @end
114 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACBacktraceSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACBacktraceSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-12-24.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACBacktrace.h"
10 | #import "RACScheduler.h"
11 |
12 | #ifdef DEBUG
13 |
14 | static RACBacktrace *previousBacktrace;
15 |
16 | static void capturePreviousBacktrace(void *context) {
17 | previousBacktrace = [RACBacktrace captureBacktrace].previousThreadBacktrace;
18 | }
19 |
20 | SpecBegin(RACBacktrace)
21 |
22 | __block dispatch_block_t block;
23 |
24 | beforeEach(^{
25 | expect([RACBacktrace captureBacktrace].previousThreadBacktrace).to.beNil();
26 | previousBacktrace = nil;
27 |
28 | block = ^{
29 | capturePreviousBacktrace(NULL);
30 | };
31 | });
32 |
33 | it(@"should capture the current backtrace", ^{
34 | RACBacktrace *backtrace = [RACBacktrace captureBacktrace];
35 | expect(backtrace).notTo.beNil();
36 | });
37 |
38 | describe(@"with a GCD queue", ^{
39 | __block dispatch_queue_t queue;
40 |
41 | beforeEach(^{
42 | queue = dispatch_queue_create("com.github.ReactiveCocoa.RACBacktraceSpec", DISPATCH_QUEUE_SERIAL);
43 | });
44 |
45 | afterEach(^{
46 | dispatch_barrier_sync(queue, ^{});
47 | dispatch_release(queue);
48 | });
49 |
50 | it(@"should trace across dispatch_async", ^{
51 | dispatch_async(queue, block);
52 | expect(previousBacktrace).willNot.beNil();
53 | });
54 |
55 | it(@"should trace across dispatch_async to the main thread", ^{
56 | dispatch_async(queue, ^{
57 | dispatch_async(dispatch_get_main_queue(), block);
58 | });
59 |
60 | expect(previousBacktrace).willNot.beNil();
61 | });
62 |
63 | it(@"should trace across dispatch_async_f", ^{
64 | dispatch_async_f(queue, NULL, &capturePreviousBacktrace);
65 | expect(previousBacktrace).willNot.beNil();
66 | });
67 |
68 | it(@"should trace across dispatch_barrier_async", ^{
69 | dispatch_barrier_async(queue, block);
70 | expect(previousBacktrace).willNot.beNil();
71 | });
72 |
73 | it(@"should trace across dispatch_barrier_async_f", ^{
74 | dispatch_barrier_async_f(queue, NULL, &capturePreviousBacktrace);
75 | expect(previousBacktrace).willNot.beNil();
76 | });
77 |
78 | it(@"should trace across dispatch_after", ^{
79 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1), queue, block);
80 | expect(previousBacktrace).willNot.beNil();
81 | });
82 |
83 | it(@"should trace across dispatch_after_f", ^{
84 | dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 1), queue, NULL, &capturePreviousBacktrace);
85 | expect(previousBacktrace).willNot.beNil();
86 | });
87 | });
88 |
89 | it(@"should trace across a RACScheduler", ^{
90 | [[RACScheduler scheduler] schedule:block];
91 | expect(previousBacktrace).willNot.beNil();
92 | });
93 |
94 | it(@"should trace across an NSOperationQueue", ^{
95 | NSOperationQueue *queue = [[NSOperationQueue alloc] init];
96 | [queue addOperationWithBlock:block];
97 | expect(previousBacktrace).willNot.beNil();
98 | });
99 |
100 | SpecEnd
101 |
102 | #endif
103 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACPropertySubject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySubject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Uri Baghin on 16/12/2012.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACPropertySubject+Private.h"
10 | #import "RACBinding+Private.h"
11 | #import "RACDisposable.h"
12 | #import "RACReplaySubject.h"
13 | #import "RACTuple.h"
14 | #import "EXTScope.h"
15 |
16 | @interface RACPropertySubject ()
17 |
18 | // The signal passed to `-initWithSignal:subscriber:`. Refer to the method's
19 | // docs for details.
20 | @property (nonatomic, readonly, strong) RACSignal *signal;
21 |
22 | // The subscriber passed to `-initWithSignal:subscriber:`. Refer to the method's
23 | // docs for details.
24 | @property (nonatomic, readonly, strong) id subscriber;
25 |
26 | // The signal exposed to callers. The property will behave like this signal
27 | // towards it's subscribers.
28 | @property (nonatomic, readonly, strong) RACSignal *exposedSignal;
29 |
30 | // The subscriber exposed to callers. The property will behave like this
31 | // subscriber towards the signals it's subscribed to.
32 | @property (nonatomic, readonly, strong) id exposedSubscriber;
33 |
34 | @end
35 |
36 | @implementation RACPropertySubject
37 |
38 | #pragma mark NSObject
39 |
40 | - (id)init {
41 | RACReplaySubject *backing = [RACReplaySubject replaySubjectWithCapacity:1];
42 | [backing sendNext:[RACTuple tupleWithObjects:RACTupleNil.tupleNil, RACTupleNil.tupleNil, nil]];
43 | return [self initWithSignal:backing subscriber:backing];
44 | }
45 |
46 | #pragma mark RACSignal
47 |
48 | - (RACDisposable *)subscribe:(id)subscriber {
49 | return [self.exposedSignal subscribe:subscriber];
50 | }
51 |
52 | #pragma mark
53 |
54 | - (void)sendNext:(id)value {
55 | [self.exposedSubscriber sendNext:value];
56 | }
57 |
58 | - (void)sendError:(NSError *)error {
59 | [self.exposedSubscriber sendError:error];
60 | }
61 |
62 | - (void)sendCompleted {
63 | [self.exposedSubscriber sendCompleted];
64 | }
65 |
66 | - (void)didSubscribeWithDisposable:(RACDisposable *)disposable {
67 | [self.exposedSubscriber didSubscribeWithDisposable:disposable];
68 | }
69 |
70 | #pragma mark API
71 |
72 | - (instancetype)initWithSignal:(RACSignal *)signal subscriber:(id)subscriber {
73 | self = [super init];
74 | if (self == nil) return nil;
75 |
76 | _signal = signal;
77 | _subscriber = subscriber;
78 |
79 | @weakify(self);
80 | _exposedSignal = [_signal map:^(RACTuple *value) {
81 | return value.first;
82 | }];
83 | _exposedSubscriber = [RACSubscriber subscriberWithNext:^(id x) {
84 | [subscriber sendNext:[RACTuple tupleWithObjects:x, RACTupleNil.tupleNil, nil]];
85 | } error:^(NSError *error) {
86 | @strongify(self);
87 | NSCAssert(NO, @"Received error in RACPropertySubject %@: %@", self, error);
88 |
89 | // Log the error if we're running with assertions disabled.
90 | NSLog(@"Received error in RACPropertySubject %@: %@", self, error);
91 | } completed:nil];
92 |
93 | return self;
94 | }
95 |
96 | + (instancetype)property {
97 | return [self subject];
98 | }
99 |
100 | - (RACBinding *)binding {
101 | return [[RACBinding alloc] initWithSignal:self.signal subscriber:self.subscriber];
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/NSObject+RACKVOWrapper.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+RACKVOWrapper.m
3 | // GitHub
4 | //
5 | // Created by Josh Abernathy on 10/11/11.
6 | // Copyright (c) 2011 GitHub. All rights reserved.
7 | //
8 |
9 | #import "NSObject+RACKVOWrapper.h"
10 | #import "NSObject+RACKVOWrapperPrivate.h"
11 | #import "RACSwizzling.h"
12 | #import "RACKVOTrampoline.h"
13 | #import
14 |
15 | static void *RACKVOTrampolinesKey = &RACKVOTrampolinesKey;
16 |
17 | static NSMutableSet *swizzledClasses() {
18 | static dispatch_once_t onceToken;
19 | static NSMutableSet *swizzledClasses = nil;
20 | dispatch_once(&onceToken, ^{
21 | swizzledClasses = [[NSMutableSet alloc] init];
22 | });
23 |
24 | return swizzledClasses;
25 | }
26 |
27 | @implementation NSObject (RACKVOWrapper)
28 |
29 | - (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
30 | void (^swizzle)(Class) = ^(Class classToSwizzle){
31 | NSString *className = NSStringFromClass(classToSwizzle);
32 | if ([swizzledClasses() containsObject:className]) return;
33 |
34 | SEL deallocSelector = sel_registerName("dealloc");
35 |
36 | Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);
37 | void (*originalDealloc)(id, SEL) = (__typeof__(originalDealloc))method_getImplementation(deallocMethod);
38 |
39 | id newDealloc = ^(__unsafe_unretained NSObject *self) {
40 | NSSet *trampolines;
41 |
42 | @synchronized (self) {
43 | trampolines = [self.RACKVOTrampolines copy];
44 | self.RACKVOTrampolines = nil;
45 | }
46 |
47 | // If we're currently delivering a KVO callback then niling
48 | // the trampoline set might not dealloc the trampoline and
49 | // therefore make them be dealloc'd. So we need to manually
50 | // stop observing on all of them as well.
51 | [trampolines makeObjectsPerformSelector:@selector(stopObserving)];
52 |
53 | originalDealloc(self, deallocSelector);
54 | };
55 |
56 | class_replaceMethod(classToSwizzle, deallocSelector, imp_implementationWithBlock(newDealloc), method_getTypeEncoding(deallocMethod));
57 |
58 | [swizzledClasses() addObject:className];
59 | };
60 |
61 | // We swizzle the dealloc for both the object being observed and the
62 | // observer of the observation. Because when either gets dealloc'd, we need
63 | // to tear down the observation.
64 | @synchronized (swizzledClasses()) {
65 | swizzle(self.class);
66 | swizzle(observer.class);
67 | }
68 |
69 | return [[RACKVOTrampoline alloc] initWithTarget:self observer:observer keyPath:keyPath options:options block:block];
70 | }
71 |
72 | - (void)rac_addKVOTrampoline:(RACKVOTrampoline *)trampoline {
73 | NSCParameterAssert(trampoline != nil);
74 |
75 | @synchronized (self) {
76 | if (self.RACKVOTrampolines == nil) {
77 | self.RACKVOTrampolines = [NSMutableArray array];
78 | }
79 |
80 | [self.RACKVOTrampolines addObject:trampoline];
81 | }
82 | }
83 |
84 | - (void)rac_removeKVOTrampoline:(RACKVOTrampoline *)trampoline {
85 | @synchronized (self) {
86 | [self.RACKVOTrampolines removeObject:trampoline];
87 | }
88 | }
89 |
90 | - (NSMutableArray *)RACKVOTrampolines {
91 | return objc_getAssociatedObject(self, RACKVOTrampolinesKey);
92 | }
93 |
94 | - (void)setRACKVOTrampolines:(NSMutableArray *)set {
95 | objc_setAssociatedObject(self, RACKVOTrampolinesKey, set, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
96 | }
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACSubscriberSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACSubscriberSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-11-27.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACSubscriberExamples.h"
10 |
11 | #import "RACSubscriber.h"
12 | #import
13 |
14 | SpecBegin(RACSubscriber)
15 |
16 | __block RACSubscriber *subscriber;
17 | __block NSMutableArray *values;
18 |
19 | __block volatile BOOL finished;
20 | __block volatile int32_t nextsAfterFinished;
21 |
22 | __block BOOL success;
23 | __block NSError *error;
24 |
25 | beforeEach(^{
26 | values = [NSMutableArray array];
27 |
28 | finished = NO;
29 | nextsAfterFinished = 0;
30 |
31 | success = YES;
32 | error = nil;
33 |
34 | subscriber = [RACSubscriber subscriberWithNext:^(id value) {
35 | if (finished) OSAtomicIncrement32Barrier(&nextsAfterFinished);
36 |
37 | [values addObject:value];
38 | } error:^(NSError *e) {
39 | error = e;
40 | success = NO;
41 | } completed:^{
42 | success = YES;
43 | }];
44 | });
45 |
46 | itShouldBehaveLike(RACSubscriberExamples, ^{
47 | return @{
48 | RACSubscriberExampleSubscriber: subscriber,
49 | RACSubscriberExampleValuesReceivedBlock: [^{ return [values copy]; } copy],
50 | RACSubscriberExampleErrorReceivedBlock: [^{ return error; } copy],
51 | RACSubscriberExampleSuccessBlock: [^{ return success; } copy]
52 | };
53 | });
54 |
55 | describe(@"finishing", ^{
56 | __block void (^sendValues)(void);
57 | __block BOOL expectedSuccess;
58 |
59 | __block dispatch_group_t dispatchGroup;
60 | __block dispatch_queue_t concurrentQueue;
61 |
62 | beforeEach(^{
63 | dispatchGroup = dispatch_group_create();
64 | expect(dispatchGroup).notTo.beNil();
65 |
66 | concurrentQueue = dispatch_queue_create("com.github.ReactiveCocoa.RACSubscriberSpec", DISPATCH_QUEUE_CONCURRENT);
67 | expect(concurrentQueue).notTo.beNil();
68 |
69 | dispatch_suspend(concurrentQueue);
70 |
71 | sendValues = [^{
72 | for (NSUInteger i = 0; i < 15; i++) {
73 | dispatch_group_async(dispatchGroup, concurrentQueue, ^{
74 | [subscriber sendNext:@(i)];
75 | });
76 | }
77 | } copy];
78 |
79 | sendValues();
80 | });
81 |
82 | afterEach(^{
83 | sendValues();
84 | dispatch_resume(concurrentQueue);
85 |
86 | // Time out after one second.
87 | dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
88 | expect(dispatch_group_wait(dispatchGroup, time)).to.equal(0);
89 |
90 | dispatch_release(dispatchGroup);
91 | dispatchGroup = NULL;
92 |
93 | dispatch_release(concurrentQueue);
94 | concurrentQueue = NULL;
95 |
96 | expect(nextsAfterFinished).to.equal(0);
97 |
98 | if (expectedSuccess) {
99 | expect(success).to.beTruthy();
100 | expect(error).to.beNil();
101 | } else {
102 | expect(success).to.beFalsy();
103 | }
104 | });
105 |
106 | it(@"should never invoke next after sending completed", ^{
107 | expectedSuccess = YES;
108 |
109 | dispatch_group_async(dispatchGroup, concurrentQueue, ^{
110 | [subscriber sendCompleted];
111 |
112 | finished = YES;
113 | OSMemoryBarrier();
114 | });
115 | });
116 |
117 | it(@"should never invoke next after sending error", ^{
118 | expectedSuccess = NO;
119 |
120 | dispatch_group_async(dispatchGroup, concurrentQueue, ^{
121 | [subscriber sendError:nil];
122 |
123 | finished = YES;
124 | OSMemoryBarrier();
125 | });
126 | });
127 | });
128 |
129 | SpecEnd
130 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACPropertySignalExamples.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACPropertySignalExamples.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 9/28/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACTestObject.h"
10 |
11 | #import "EXTKeyPathCoding.h"
12 | #import "NSObject+RACPropertySubscribing.h"
13 | #import "RACDisposable.h"
14 | #import "RACSubject.h"
15 |
16 | NSString * const RACPropertySignalExamples = @"RACPropertySignalExamples";
17 | NSString * const RACPropertySignalExamplesSetupBlock = @"RACPropertySignalExamplesSetupBlock";
18 |
19 | SharedExampleGroupsBegin(RACPropertySignalExamples)
20 |
21 | sharedExamplesFor(RACPropertySignalExamples, ^(NSDictionary *data) {
22 | __block RACTestObject *testObject = nil;
23 | __block void (^setupBlock)(RACTestObject *, NSString *keyPath, RACSignal *);
24 |
25 | beforeEach(^{
26 | setupBlock = data[RACPropertySignalExamplesSetupBlock];
27 | testObject = [[RACTestObject alloc] init];
28 | });
29 |
30 | it(@"should set the value of the property with the latest value from the signal", ^{
31 | RACSubject *subject = [RACSubject subject];
32 | setupBlock(testObject, @keypath(testObject.objectValue), subject);
33 | expect(testObject.objectValue).to.beNil();
34 |
35 | [subject sendNext:@1];
36 | expect(testObject.objectValue).to.equal(@1);
37 |
38 | [subject sendNext:@2];
39 | expect(testObject.objectValue).to.equal(@2);
40 |
41 | [subject sendNext:nil];
42 | expect(testObject.objectValue).to.beNil();
43 | });
44 |
45 | it(@"should set the value of a non-object property with the latest value from the signal", ^{
46 | RACSubject *subject = [RACSubject subject];
47 | setupBlock(testObject, @keypath(testObject.integerValue), subject);
48 | expect(testObject.integerValue).to.equal(0);
49 |
50 | [subject sendNext:@1];
51 | expect(testObject.integerValue).to.equal(1);
52 |
53 | [subject sendNext:@2];
54 | expect(testObject.integerValue).to.equal(2);
55 |
56 | [subject sendNext:@0];
57 | expect(testObject.integerValue).to.equal(0);
58 |
59 | [subject sendNext:nil];
60 | expect(testObject.integerValue).to.equal(0);
61 | });
62 |
63 | it(@"should retain intermediate signals when binding", ^{
64 | RACSubject *subject = [RACSubject subject];
65 | expect(subject).notTo.beNil();
66 |
67 | __block BOOL deallocd = NO;
68 |
69 | @autoreleasepool {
70 | @autoreleasepool {
71 | RACSignal *intermediateSignal = [subject map:^(NSNumber *num) {
72 | return @(num.integerValue + 1);
73 | }];
74 |
75 | expect(intermediateSignal).notTo.beNil();
76 |
77 | [intermediateSignal rac_addDeallocDisposable:[RACDisposable disposableWithBlock:^{
78 | deallocd = YES;
79 | }]];
80 |
81 | setupBlock(testObject, @keypath(testObject.integerValue), intermediateSignal);
82 | }
83 |
84 | // Spin the run loop to account for RAC magic that retains the
85 | // signal for a single iteration.
86 | [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
87 | }
88 |
89 | expect(deallocd).to.beFalsy();
90 |
91 | [subject sendNext:@5];
92 | expect(testObject.integerValue).to.equal(6);
93 |
94 | [subject sendNext:@6];
95 | expect(testObject.integerValue).to.equal(7);
96 |
97 | expect(deallocd).to.beFalsy();
98 | [subject sendCompleted];
99 |
100 | // Can't test deallocd again, because it's legal for the chain to be
101 | // retained until the object or the original signal is destroyed.
102 | });
103 | });
104 |
105 | SharedExampleGroupsEnd
106 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACReplaySubject.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACReplaySubject.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 3/14/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACReplaySubject.h"
10 | #import "RACDisposable.h"
11 | #import "RACScheduler+Private.h"
12 | #import "RACSubscriber.h"
13 | #import "RACTuple.h"
14 | #import "RACCompoundDisposable.h"
15 | #import
16 |
17 | const NSUInteger RACReplaySubjectUnlimitedCapacity = 0;
18 |
19 | @interface RACReplaySubject ()
20 |
21 | @property (nonatomic, assign, readonly) NSUInteger capacity;
22 |
23 | // These properties should only be modified while synchronized on self.
24 | @property (nonatomic, strong, readonly) NSMutableArray *valuesReceived;
25 | @property (nonatomic, assign) BOOL hasCompleted;
26 | @property (nonatomic, assign) BOOL hasError;
27 | @property (nonatomic, strong) NSError *error;
28 |
29 | @end
30 |
31 |
32 | @implementation RACReplaySubject
33 |
34 | #pragma mark Lifecycle
35 |
36 | + (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity {
37 | return [[self alloc] initWithCapacity:capacity];
38 | }
39 |
40 | - (instancetype)init {
41 | return [self initWithCapacity:RACReplaySubjectUnlimitedCapacity];
42 | }
43 |
44 | - (instancetype)initWithCapacity:(NSUInteger)capacity {
45 | self = [super init];
46 | if (self == nil) return nil;
47 |
48 | _capacity = capacity;
49 | _valuesReceived = [NSMutableArray arrayWithCapacity:capacity];
50 |
51 | return self;
52 | }
53 |
54 | #pragma mark RACSignal
55 |
56 | - (RACDisposable *)subscribe:(id)subscriber {
57 | __block volatile uint32_t disposed = 0;
58 |
59 | RACDisposable *stopDisposable = [RACDisposable disposableWithBlock:^{
60 | OSAtomicOr32Barrier(1, &disposed);
61 | }];
62 |
63 | RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ stopDisposable ]];
64 | RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
65 | @synchronized (self) {
66 | for (id value in self.valuesReceived) {
67 | if (disposed != 0) return;
68 |
69 | [subscriber sendNext:([value isKindOfClass:RACTupleNil.class] ? nil : value)];
70 | }
71 |
72 | if (disposed != 0) return;
73 |
74 | if (self.hasCompleted) {
75 | [subscriber sendCompleted];
76 | } else if (self.hasError) {
77 | [subscriber sendError:self.error];
78 | } else {
79 | RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
80 | [compoundDisposable addDisposable:subscriptionDisposable];
81 | }
82 | }
83 | }];
84 |
85 | if (schedulingDisposable != nil) [compoundDisposable addDisposable:schedulingDisposable];
86 |
87 | return compoundDisposable;
88 | }
89 |
90 | #pragma mark RACSubscriber
91 |
92 | - (void)sendNext:(id)value {
93 | @synchronized (self) {
94 | [self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
95 | [super sendNext:value];
96 |
97 | if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
98 | [self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
99 | }
100 | }
101 | }
102 |
103 | - (void)sendCompleted {
104 | @synchronized (self) {
105 | self.hasCompleted = YES;
106 | [super sendCompleted];
107 | }
108 | }
109 |
110 | - (void)sendError:(NSError *)e {
111 | @synchronized (self) {
112 | self.hasError = YES;
113 | self.error = e;
114 | [super sendError:e];
115 | }
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoaTests/RACMulticastConnectionSpec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACMulticastConnectionSpec.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Josh Abernathy on 10/8/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACMulticastConnection.h"
10 | #import "RACDisposable.h"
11 | #import "RACSignal+Operations.h"
12 | #import "RACSubscriber.h"
13 | #import "RACReplaySubject.h"
14 |
15 | SpecBegin(RACMulticastConnection)
16 |
17 | __block NSUInteger subscriptionCount = 0;
18 | __block RACMulticastConnection *connection;
19 | __block BOOL disposed = NO;
20 |
21 | beforeEach(^{
22 | subscriptionCount = 0;
23 | disposed = NO;
24 | connection = [[RACSignal createSignal:^(id subscriber) {
25 | subscriptionCount++;
26 | return [RACDisposable disposableWithBlock:^{
27 | disposed = YES;
28 | }];
29 | }] publish];
30 | expect(subscriptionCount).to.equal(0);
31 | });
32 |
33 | describe(@"-connect", ^{
34 | it(@"should subscribe to the underlying signal", ^{
35 | [connection connect];
36 | expect(subscriptionCount).to.equal(1);
37 | });
38 |
39 | it(@"should return the same disposable for each invocation", ^{
40 | RACDisposable *d1 = [connection connect];
41 | RACDisposable *d2 = [connection connect];
42 | expect(d1).to.equal(d2);
43 | expect(subscriptionCount).to.equal(1);
44 | });
45 |
46 | it(@"shouldn't reconnect after disposal", ^{
47 | RACDisposable *disposable1 = [connection connect];
48 | expect(subscriptionCount).to.equal(1);
49 |
50 | [disposable1 dispose];
51 |
52 | RACDisposable *disposable2 = [connection connect];
53 | expect(subscriptionCount).to.equal(1);
54 | expect(disposable1).to.equal(disposable2);
55 | });
56 | });
57 |
58 | describe(@"-autoconnect", ^{
59 | __block RACSignal *autoconnectedSignal;
60 |
61 | beforeEach(^{
62 | autoconnectedSignal = [connection autoconnect];
63 | });
64 |
65 | it(@"should subscribe to the multicasted signal on the first subscription", ^{
66 | expect(subscriptionCount).to.equal(0);
67 |
68 | [autoconnectedSignal subscribeNext:^(id x) {}];
69 | expect(subscriptionCount).to.equal(1);
70 |
71 | [autoconnectedSignal subscribeNext:^(id x) {}];
72 | expect(subscriptionCount).to.equal(1);
73 | });
74 |
75 | it(@"should dispose of the multicasted subscription when the signal has no subscribers", ^{
76 | RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
77 |
78 | expect(disposed).to.beFalsy();
79 | [disposable dispose];
80 | expect(disposed).to.beTruthy();
81 | });
82 |
83 | it(@"shouldn't reconnect after disposal", ^{
84 | RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
85 | expect(subscriptionCount).to.equal(1);
86 | [disposable dispose];
87 |
88 | disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
89 | expect(subscriptionCount).to.equal(1);
90 | [disposable dispose];
91 | });
92 |
93 | it(@"should replay values after disposal when multicasted to a replay subject", ^{
94 | RACSubject *subject = [RACSubject subject];
95 | RACSignal *signal = [[subject multicast:[RACReplaySubject subject]] autoconnect];
96 |
97 | NSMutableArray *results1 = [NSMutableArray array];
98 | RACDisposable *disposable = [signal subscribeNext:^(id x) {
99 | [results1 addObject:x];
100 | }];
101 |
102 | [subject sendNext:@1];
103 | [subject sendNext:@2];
104 |
105 | expect(results1).to.equal((@[ @1, @2 ]));
106 | [disposable dispose];
107 |
108 | NSMutableArray *results2 = [NSMutableArray array];
109 | [signal subscribeNext:^(id x) {
110 | [results2 addObject:x];
111 | }];
112 | expect(results2).will.equal((@[ @1, @2 ]));
113 | });
114 | });
115 |
116 | SpecEnd
117 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACArraySequence.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACArraySequence.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Justin Spahr-Summers on 2012-10-29.
6 | // Copyright (c) 2012 GitHub. All rights reserved.
7 | //
8 |
9 | #import "RACArraySequence.h"
10 |
11 | @interface RACArraySequence ()
12 |
13 | // Redeclared from the superclass and marked deprecated to prevent using `array`
14 | // where `backingArray` is intended.
15 | @property (nonatomic, copy, readonly) NSArray *array __attribute__((deprecated));
16 |
17 | // The array being sequenced.
18 | @property (nonatomic, copy, readonly) NSArray *backingArray;
19 |
20 | // The index in the array from which the sequence starts.
21 | @property (nonatomic, assign, readonly) NSUInteger offset;
22 |
23 | @end
24 |
25 | @implementation RACArraySequence
26 |
27 | #pragma mark Lifecycle
28 |
29 | + (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset {
30 | NSCParameterAssert(offset <= array.count);
31 |
32 | if (offset == array.count) return self.empty;
33 |
34 | RACArraySequence *seq = [[self alloc] init];
35 | seq->_backingArray = [array copy];
36 | seq->_offset = offset;
37 | return seq;
38 | }
39 |
40 | #pragma mark RACSequence
41 |
42 | - (id)head {
43 | return [self.backingArray objectAtIndex:self.offset];
44 | }
45 |
46 | - (RACSequence *)tail {
47 | RACSequence *sequence = [self.class sequenceWithArray:self.backingArray offset:self.offset + 1];
48 | sequence.name = self.name;
49 | return sequence;
50 | }
51 |
52 | #pragma mark NSFastEnumeration
53 |
54 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id[])stackbuf count:(NSUInteger)len {
55 | NSCParameterAssert(len > 0);
56 |
57 | if (state->state >= self.backingArray.count) {
58 | // Enumeration has completed.
59 | return 0;
60 | }
61 |
62 | if (state->state == 0) {
63 | state->state = self.offset;
64 |
65 | // Since a sequence doesn't mutate, this just needs to be set to
66 | // something non-NULL.
67 | state->mutationsPtr = state->extra;
68 | }
69 |
70 | state->itemsPtr = stackbuf;
71 |
72 | NSUInteger startIndex = state->state;
73 | NSUInteger index = 0;
74 |
75 | for (id value in self.backingArray) {
76 | // Constructing an index set for -enumerateObjectsAtIndexes: can actually be
77 | // slower than just skipping the items we don't care about.
78 | if (index < startIndex) {
79 | ++index;
80 | continue;
81 | }
82 |
83 | stackbuf[index - startIndex] = value;
84 |
85 | ++index;
86 | if (index - startIndex >= len) break;
87 | }
88 |
89 | NSCAssert(index > startIndex, @"Final index (%lu) should be greater than start index (%lu)", (unsigned long)index, (unsigned long)startIndex);
90 |
91 | state->state = index;
92 | return index - startIndex;
93 | }
94 |
95 | #pragma clang diagnostic push
96 | #pragma clang diagnostic ignored "-Wdeprecated-implementations"
97 | - (NSArray *)array {
98 | return [self.backingArray subarrayWithRange:NSMakeRange(self.offset, self.backingArray.count - self.offset)];
99 | }
100 | #pragma clang diagnostic pop
101 |
102 | #pragma mark NSCoding
103 |
104 | - (id)initWithCoder:(NSCoder *)coder {
105 | self = [super initWithCoder:coder];
106 | if (self == nil) return nil;
107 |
108 | _backingArray = [coder decodeObjectForKey:@"array"];
109 | _offset = 0;
110 |
111 | return self;
112 | }
113 |
114 | - (void)encodeWithCoder:(NSCoder *)coder {
115 | // Encoding is handled in RACSequence.
116 | [super encodeWithCoder:coder];
117 | }
118 |
119 | #pragma mark NSObject
120 |
121 | - (NSString *)description {
122 | return [NSString stringWithFormat:@"<%@: %p>{ name = %@, array = %@ }", self.class, self, self.name, self.backingArray];
123 | }
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/ReactiveCocoaFramework/ReactiveCocoa/RACEventTrampoline.m:
--------------------------------------------------------------------------------
1 | //
2 | // RACEventTrampoline.m
3 | // ReactiveCocoa
4 | //
5 | // Created by Cody Krieger on 5/18/12.
6 | // Copyright (c) 2012 GitHub, Inc. All rights reserved.
7 | //
8 |
9 | #import "RACEventTrampoline.h"
10 | #import "RACSwizzling.h"
11 | #import "RACObjCRuntime.h"
12 | #import "RACDelegateProxy.h"
13 | #import
14 |
15 | const char *RACEventTrampolinesKey = "RACEventTrampolinesKey";
16 |
17 | static NSMutableDictionary *swizzledClasses() {
18 | static dispatch_once_t onceToken;
19 | static NSMutableDictionary *swizzledClasses = nil;
20 | dispatch_once(&onceToken, ^{
21 | swizzledClasses = [[NSMutableDictionary alloc] init];
22 | });
23 |
24 | return swizzledClasses;
25 | }
26 |
27 | @implementation UITextView (RACSignalSupport)
28 |
29 | - (void)rac_setDelegate:(id)delegate {
30 | Class proxyClass = [RACDelegateProxy class];
31 |
32 | if ([delegate isKindOfClass:proxyClass]) {
33 | id oldDelegate = [self delegate];
34 | [(RACDelegateProxy *)delegate setActualDelegate:oldDelegate];
35 |
36 | [self rac_setDelegate:delegate];
37 | } else if ([self.delegate isKindOfClass:proxyClass]) {
38 | [(RACDelegateProxy *)self.delegate setActualDelegate:delegate];
39 | } else {
40 | [self rac_setDelegate:delegate];
41 | }
42 | }
43 |
44 | @end
45 |
46 |
47 | @implementation RACEventTrampoline
48 |
49 | @synthesize proxy;
50 | @synthesize delegateMethod;
51 |
52 | + (instancetype)trampolineForControl:(UIControl *)control controlEvents:(UIControlEvents)controlEvents {
53 | RACEventTrampoline *trampoline = [[self alloc] init];
54 | [control addTarget:trampoline action:@selector(didGetControlEvent:) forControlEvents:controlEvents];
55 | return trampoline;
56 | }
57 |
58 | + (instancetype)trampolineForGestureRecognizer:(UIGestureRecognizer *)gesture {
59 | RACEventTrampoline *trampoline = [[self alloc] init];
60 | [gesture addTarget:trampoline action:@selector(didGetControlEvent:)];
61 |
62 | return trampoline;
63 | }
64 |
65 | + (instancetype)trampolineForTextView:(UITextView *)textView delegateMethod:(SEL)method {
66 | RACEventTrampoline *trampoline = [[self alloc] init];
67 | [trampoline setDelegateMethod:method];
68 |
69 | @synchronized(swizzledClasses()) {
70 | Class class = [textView class];
71 | NSString *keyName = NSStringFromClass(class);
72 | if ([swizzledClasses() objectForKey:keyName] == nil) {
73 | RACSwizzle(class, @selector(setDelegate:), @selector(rac_setDelegate:));
74 | [swizzledClasses() setObject:[NSNull null] forKey:keyName];
75 | }
76 | }
77 |
78 | if ([[textView delegate] isKindOfClass:[RACDelegateProxy class]]) {
79 | [(RACDelegateProxy *)textView.delegate addTrampoline:trampoline];
80 | } else {
81 | Protocol *protocol = @protocol(UITextViewDelegate);
82 |
83 | RACDelegateProxy *proxy = [RACDelegateProxy proxyWithProtocol:protocol andDelegator:textView];
84 | [proxy addTrampoline:trampoline];
85 |
86 | [textView setDelegate:(id)proxy];
87 | }
88 |
89 | return trampoline;
90 | }
91 |
92 | - (void)dealloc {
93 | [_subject sendCompleted];
94 | }
95 |
96 | - (id)init {
97 | self = [super init];
98 | if(self == nil) return nil;
99 |
100 | self.subject = [RACSubject subject];
101 |
102 | return self;
103 | }
104 |
105 | - (void)didGetControlEvent:(id)sender {
106 | [self.subject sendNext:sender];
107 | }
108 |
109 | - (void)didGetDelegateEvent:(SEL)receivedEvent sender:(id)sender {
110 | if (receivedEvent == delegateMethod) {
111 | [self didGetControlEvent:sender];
112 | }
113 | }
114 |
115 | @end
116 |
--------------------------------------------------------------------------------