Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/raccommand-fixups' (pull request R…
Browse files Browse the repository at this point in the history
  • Loading branch information
jspahrsummers committed Sep 4, 2012
2 parents 4b4abf0 + bed14ba commit cbc23c1
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 200 deletions.
1 change: 0 additions & 1 deletion GHAPIDemo/GHAPIDemo/GHDLoginViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
@property (nonatomic, copy) NSString *password;
@property (nonatomic, assign, readonly) BOOL successHidden;
@property (nonatomic, assign, readonly) BOOL loginFailedHidden;
@property (nonatomic, assign, readonly) BOOL loginEnabled;
@property (nonatomic, assign, readonly) BOOL loggingIn;
@property (nonatomic, strong, readonly) RACAsyncCommand *loginCommand;
@property (nonatomic, strong, readonly) RACSubject *didLoginSubject;
Expand Down
18 changes: 6 additions & 12 deletions GHAPIDemo/GHAPIDemo/GHDLoginViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
@interface GHDLoginViewController ()
@property (nonatomic, assign) BOOL successHidden;
@property (nonatomic, assign) BOOL loginFailedHidden;
@property (nonatomic, assign) BOOL loginEnabled;
@property (nonatomic, assign) BOOL loggingIn;
@property (nonatomic, strong) RACAsyncCommand *loginCommand;
@property (nonatomic, strong) GHDLoginView *view;
Expand All @@ -33,7 +32,6 @@ - (id)init {

self.loginFailedHidden = YES;
self.successHidden = YES;
self.loginEnabled = NO;
self.loggingIn = NO;

self.didLoginSubject = [RACSubject subject];
Expand All @@ -42,16 +40,14 @@ - (id)init {
NSLog(@"Active requests: %@", x);
}];

// Login is only enabled when they've entered both a username and password,
// and we aren't already trying to login.
[[RACSubscribable
combineLatest:[NSArray arrayWithObjects:RACAbleSelf(self.username), RACAbleSelf(self.password), RACAbleSelf(self.loginCommand.numberOfActiveExecutions), nil]
// Login is only enabled when they've entered both a username and password.
self.loginCommand = [RACAsyncCommand commandWithCanExecuteSubscribable:[RACSubscribable
combineLatest:@[ [RACAbleSelf(self.username) startWith:self.username], [RACAbleSelf(self.password) startWith:self.password] ]
reduce:^(RACTuple *xs) {
return [NSNumber numberWithBool:[[xs objectAtIndex:0] length] > 0 && [[xs objectAtIndex:1] length] > 0 && [[xs objectAtIndex:2] unsignedIntegerValue] < 1];
return @([[xs objectAtIndex:0] length] > 0 && [[xs objectAtIndex:1] length] > 0);
}]
toProperty:RAC_KEYPATH_SELF(self.loginEnabled) onObject:self];
block:NULL];

self.loginCommand = [RACAsyncCommand command];
[[self.loginCommand
injectObjectWeakly:self]
subscribeNext:^(RACTuple *t) {
Expand Down Expand Up @@ -135,12 +131,11 @@ - (void)loadView {
[self.view.passwordTextField bind:NSValueBinding toObject:self withKeyPath:RAC_KEYPATH_SELF(self.password)];
[self.view.successTextField bind:NSHiddenBinding toObject:self withKeyPath:RAC_KEYPATH_SELF(self.successHidden)];
[self.view.couldNotLoginTextField bind:NSHiddenBinding toObject:self withKeyPath:RAC_KEYPATH_SELF(self.loginFailedHidden)];
[self.view.loginButton bind:NSEnabledBinding toObject:self withKeyPath:RAC_KEYPATH_SELF(self.loginEnabled)];
[self.view.loggingInSpinner bind:NSHiddenBinding toObject:self withNegatedKeyPath:RAC_KEYPATH_SELF(self.loggingIn)];

[self.view.loggingInSpinner startAnimation:nil];

[self.view.loginButton addCommand:self.loginCommand];
self.view.loginButton.rac_command = self.loginCommand;
}


Expand All @@ -152,7 +147,6 @@ - (void)loadView {
@synthesize successHidden;
@synthesize loginFailedHidden;
@synthesize loginCommand;
@synthesize loginEnabled;
@synthesize loggingIn;
@synthesize user;
@synthesize client;
Expand Down
2 changes: 0 additions & 2 deletions RACiOSDemo/RACiOSDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,6 @@
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
Expand All @@ -422,7 +421,6 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
Expand Down
10 changes: 8 additions & 2 deletions ReactiveCocoaFramework/ReactiveCocoa.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@
8820370A15096A4F002428D3 /* RACMaybe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8820370815096A4F002428D3 /* RACMaybe.h */; settings = {ATTRIBUTES = (Public, ); }; };
8820370B15096A4F002428D3 /* RACMaybe.m in Sources */ = {isa = PBXBuildFile; fileRef = 8820370915096A4F002428D3 /* RACMaybe.m */; };
8820937C1501C8A600796685 /* RACSubscribableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8820937B1501C8A600796685 /* RACSubscribableSpec.m */; };
882CCA1E15F1564D00937D6E /* RACCommandSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 882CCA1D15F1564D00937D6E /* RACCommandSpec.m */; };
883A84DA1513964B006DB4C7 /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = 883A84D81513964B006DB4C7 /* RACBehaviorSubject.h */; settings = {ATTRIBUTES = (Public, ); }; };
883A84DB1513964B006DB4C7 /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = 883A84D91513964B006DB4C7 /* RACBehaviorSubject.m */; };
883A84DF1513B5EC006DB4C7 /* RACDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = 883A84DD1513B5EC006DB4C7 /* RACDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; };
883A84E01513B5EC006DB4C7 /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = 883A84DE1513B5EC006DB4C7 /* RACDisposable.m */; };
884476E4152367D100958F44 /* RACScopedDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = 884476E2152367D100958F44 /* RACScopedDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; };
884476E5152367D100958F44 /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = 884476E3152367D100958F44 /* RACScopedDisposable.m */; };
884848B615F658B800B11BD0 /* NSButtonRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 884848B515F658B800B11BD0 /* NSButtonRACSupportSpec.m */; };
8857BB7E152A2747009804CC /* NSObject+RACExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 8857BB7C152A2747009804CC /* NSObject+RACExtensions.h */; };
8857BB7F152A2747009804CC /* NSObject+RACExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8857BB7D152A2747009804CC /* NSObject+RACExtensions.m */; };
8857BB82152A27A9009804CC /* NSObject+RACKVOWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 8857BB81152A27A9009804CC /* NSObject+RACKVOWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -267,12 +269,14 @@
882093E71501E6CB00796685 /* NSButton+RACCommandSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSButton+RACCommandSupport.m"; sourceTree = "<group>"; };
882093E91501E6EE00796685 /* RACCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACCommand.h; sourceTree = "<group>"; };
882093EA1501E6EE00796685 /* RACCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCommand.m; sourceTree = "<group>"; };
882CCA1D15F1564D00937D6E /* RACCommandSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCommandSpec.m; sourceTree = "<group>"; };
883A84D81513964B006DB4C7 /* RACBehaviorSubject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACBehaviorSubject.h; sourceTree = "<group>"; };
883A84D91513964B006DB4C7 /* RACBehaviorSubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACBehaviorSubject.m; sourceTree = "<group>"; };
883A84DD1513B5EC006DB4C7 /* RACDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDisposable.h; sourceTree = "<group>"; };
883A84DE1513B5EC006DB4C7 /* RACDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDisposable.m; sourceTree = "<group>"; };
884476E2152367D100958F44 /* RACScopedDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACScopedDisposable.h; sourceTree = "<group>"; };
884476E3152367D100958F44 /* RACScopedDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACScopedDisposable.m; sourceTree = "<group>"; };
884848B515F658B800B11BD0 /* NSButtonRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSButtonRACSupportSpec.m; sourceTree = "<group>"; };
8857BB7C152A2747009804CC /* NSObject+RACExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACExtensions.h"; sourceTree = "<group>"; };
8857BB7D152A2747009804CC /* NSObject+RACExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACExtensions.m"; sourceTree = "<group>"; };
8857BB81152A27A9009804CC /* NSObject+RACKVOWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACKVOWrapper.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -331,7 +335,6 @@
88D4AB481510F8F10011494F /* RACAsyncSubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACAsyncSubject.m; sourceTree = "<group>"; };
88DA309515071CBA00C19D0F /* RACValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACValueTransformer.h; sourceTree = "<group>"; };
88DA309615071CBA00C19D0F /* RACValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACValueTransformer.m; sourceTree = "<group>"; };
88DA30B61507CC3900C19D0F /* RACCommand+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RACCommand+Private.h"; sourceTree = "<group>"; };
88DA30D31508051F00C19D0F /* RACSpecs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RACSpecs.h; sourceTree = "<group>"; };
88DE7CD2150459E800C722C5 /* RACAsyncCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACAsyncCommand.h; sourceTree = "<group>"; };
88DE7CD3150459E800C722C5 /* RACAsyncCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACAsyncCommand.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -566,6 +569,8 @@
866557A51557086B00B39EB5 /* RACExtensionsSpec.m */,
889D0A7F15974B2A00F833E3 /* RACSubjectSpec.m */,
D041376815D2281C004BBF80 /* RACKVOWrapperSpec.m */,
882CCA1D15F1564D00937D6E /* RACCommandSpec.m */,
884848B515F658B800B11BD0 /* NSButtonRACSupportSpec.m */,
);
path = ReactiveCocoaTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -623,7 +628,6 @@
88E2C6B3153C771C00C7493C /* RACScheduler.m */,
882093E91501E6EE00796685 /* RACCommand.h */,
882093EA1501E6EE00796685 /* RACCommand.m */,
88DA30B61507CC3900C19D0F /* RACCommand+Private.h */,
88DE7CD2150459E800C722C5 /* RACAsyncCommand.h */,
88DE7CD3150459E800C722C5 /* RACAsyncCommand.m */,
885A3230153CF9EF00486A61 /* RACCollection.h */,
Expand Down Expand Up @@ -1049,6 +1053,8 @@
866557A61557086B00B39EB5 /* RACExtensionsSpec.m in Sources */,
889D0A8015974B2A00F833E3 /* RACSubjectSpec.m in Sources */,
D041376915D2281C004BBF80 /* RACKVOWrapperSpec.m in Sources */,
882CCA1E15F1564D00937D6E /* RACCommandSpec.m in Sources */,
884848B615F658B800B11BD0 /* NSButtonRACSupportSpec.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@

@interface NSButton (RACCommandSupport)

// Adds the given command to the button. The command's `canExecuteValue`
// controls the button's enabledness. The command's `-canExecute:` and
// `-execute:` are passed the action's sender.
// Sets the button's command. When the button is clicked, the command is
// executed with the sender of the event. The button's enabledness is bound
// to the command's `canExecute`.
//
// Note: this will reset the button's target and action.
//
// command - the command to add. Cannot be nil.
- (void)addCommand:(RACCommand *)command;
@property (nonatomic, strong) RACCommand *rac_command;

@end
59 changes: 24 additions & 35 deletions ReactiveCocoaFramework/ReactiveCocoa/NSButton+RACCommandSupport.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,43 @@
//

#import "NSButton+RACCommandSupport.h"
#import "NSObject+RACPropertySubscribing.h"
#import "RACCommand.h"

#import <objc/runtime.h>

static void * NSButtonRACCommandsKey = &NSButtonRACCommandsKey;

@interface NSButton ()
@property (nonatomic, readonly) NSMutableArray *commands;
@end

static void * NSButtonRACCommandKey = &NSButtonRACCommandKey;

@implementation NSButton (RACCommandSupport)

- (void)addCommand:(RACCommand *)command {
NSParameterAssert(command != nil);

[self.commands addObject:command];

[self hijackActionAndTargetIfNeeded];
- (RACCommand *)rac_command {
return objc_getAssociatedObject(self, NSButtonRACCommandKey);
}

- (void)hijackActionAndTargetIfNeeded {
SEL hijackSelector = @selector(RACCommandsPerformAction:);
if([self target] != self || [self action] != hijackSelector) {
if([self action] != NULL) NSLog(@"WARNING: -[NSButton addCommand:] hijacks the button's existing target and action.");

[self setTarget:self];
[self setAction:hijackSelector];
}
- (void)setRac_command:(RACCommand *)command {
objc_setAssociatedObject(self, NSButtonRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

[self unbind:NSEnabledBinding];
self.enabled = command != nil ? command.canExecute : YES;

if (command == nil) return;

[self bind:NSEnabledBinding toObject:self.rac_command withKeyPath:@"canExecute" options:nil];

[self rac_hijackActionAndTargetIfNeeded];
}

- (void)RACCommandsPerformAction:(id)sender {
for(RACCommand *command in self.commands) {
if([command canExecute:sender]) {
[command execute:sender];
}
}
- (void)rac_hijackActionAndTargetIfNeeded {
SEL hijackSelector = @selector(rac_commandPerformAction:);
if (self.target == self && self.action == hijackSelector) return;

if (self.target != nil) NSLog(@"WARNING: -[NSButton rac_setCommand:] hijacks the button's existing target and action.");

self.target = self;
self.action = hijackSelector;
}

- (NSMutableArray *)commands {
NSMutableArray *c = objc_getAssociatedObject(self, NSButtonRACCommandsKey);
if(c == nil) {
c = [NSMutableArray array];
objc_setAssociatedObject(self, NSButtonRACCommandsKey, c, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

return c;
- (void)rac_commandPerformAction:(id)sender {
[self.rac_command execute:sender];
}

@end
12 changes: 7 additions & 5 deletions ReactiveCocoaFramework/ReactiveCocoa/RACAsyncCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@class RACAsyncSubject;


// An async command is a command that can run asynchronous functions when the
// An async command is a command that can run asynchronous blocks when the
// command is executed.
@interface RACAsyncCommand : RACCommand

Expand All @@ -20,14 +20,16 @@
// NSOperationQueueDefaultMaxConcurrentOperationCount.
@property (nonatomic, strong) NSOperationQueue *operationQueue;

// The maximum number of concurrent executions allowed. `-canExecute:` will
// return NO if the number of active executions is greater than or equal to
// this. `canExecuteValue` is updated as the number of concurrent calls changes.
// The maximum number of concurrent executions allowed.
@property (nonatomic, assign) NSUInteger maxConcurrentExecutions;

// The number of active executions.
// The number of active executions. When this is equal to `maxConcurrentExecutions`,
// `canExecute` will be NO.
@property (readonly, assign) NSUInteger numberOfActiveExecutions;

// Creates a new command that can always be executed and has no execution block.
+ (instancetype)command;

// Adds a new async block to be called when the command executes.
//
// block - a new block to perform when the command is executed. Cannot be nil.
Expand Down
Loading

0 comments on commit cbc23c1

Please sign in to comment.