From fd86b388375c0fda19203245d4897a9df57bacf4 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Fri, 21 Feb 2014 16:22:32 -0800 Subject: [PATCH 01/15] adding support for zero argument --- PubSub.h | 30 +++++++++++++++++-- .../TestPubSub/TestPubSub/AppDelegate.m | 8 ++++- .../TestPubSub/TestPubSub/Notifications.h | 5 +++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/PubSub.h b/PubSub.h index 6daee94..d58d8ed 100644 --- a/PubSub.h +++ b/PubSub.h @@ -19,11 +19,35 @@ @end -#define PubSub(name, type) \ + + +// Variable expansion with variable arguments thanks to +// http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments + +#define PubSubWithZeroArgs(name) \ +@interface Pub (PubSub_ ## name ## _Category) \ ++ (void) name; \ +@end\ +@interface Sub (PubSub_ ## name ## _Category)\ ++ (void) while:(id)obj name:(void(^)(void))callback;\ +@end + +#define PubSubWithOneArg(name, type) \ @interface Pub (PubSub_ ## name ## _Category) \ -+ (void) name:(type*)arg; \ ++ (void) name:(type)arg; \ @end\ @interface Sub (PubSub_ ## name ## _Category)\ -+ (void) while:(id)obj name:(void(^)(type*))callback;\ ++ (void) while:(id)obj name:(void(^)(type))callback;\ @end + +#define _ARG2(_0, _1, _2, ...) _2 +#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0) + +#define _ONE_OR_TWO_ARGS_1(a) PubSubWithZeroArgs(a) +#define _ONE_OR_TWO_ARGS_2(a, b) PubSubWithOneArg(a,b) + +#define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__) +#define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__) + +#define PubSub(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__) \ No newline at end of file diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index 8af12b3..3bd5d1c 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -23,13 +23,19 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self.window makeKeyAndVisible]; keeper = [[NSObject alloc] init]; - + [Sub while:keeper nicknameChanged:^(NSString* newNickname) { NSLog(@"nickname changed to: %@", newNickname); }]; [Pub nicknameChanged:@"A"]; + + [Sub while:keeper testWithZeroArgs:^{ + NSLog(@"sub fired with zero args"); + }]; + [Pub testWithZeroArgs]; + [self performSelector:@selector(b) withObject:nil afterDelay:.1]; [self performSelector:@selector(c) withObject:nil afterDelay:.15]; [self performSelector:@selector(d) withObject:nil afterDelay:.2]; diff --git a/TestProject/TestPubSub/TestPubSub/Notifications.h b/TestProject/TestPubSub/TestPubSub/Notifications.h index 66ea660..9b373ae 100644 --- a/TestProject/TestPubSub/TestPubSub/Notifications.h +++ b/TestProject/TestPubSub/TestPubSub/Notifications.h @@ -9,4 +9,7 @@ #import #import "PubSub.h" -PubSub(nicknameChanged, NSString) +PubSub(nicknameChanged, NSString*) + + +PubSub(testWithZeroArgs) From cacbbf660a46ece14bfc47cb88ea784f833f1ae4 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Sat, 22 Feb 2014 09:16:49 -0800 Subject: [PATCH 02/15] update gitignore to ignore VCS files --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 97f7c15..12cedc8 100644 --- a/.gitignore +++ b/.gitignore @@ -155,4 +155,11 @@ xcuserdata #### # UNKNOWN: recommended by others, but I can't discover what these files are # -# ...none. Everything is now explained. \ No newline at end of file +# ...none. Everything is now explained. + + +#### +# Xcode VCS metadata +# + +*.xccheckout From 4f9d951bc12d92b4a29ee8426d72ba308a6042fd Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Mon, 24 Feb 2014 10:14:58 -0800 Subject: [PATCH 03/15] update readme with zero arguments sample --- readme.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 72a9150..611a606 100644 --- a/readme.md +++ b/readme.md @@ -42,14 +42,23 @@ in all your classes. You can skip this step if you want to do it differently. In `Notifications.h` you will use a preprocessor statement to declare your notifications. Declare one per line. For example: - PubSub(nameChanged, NSString) - + PubSub(somethingHappened) // zero arguments + + PubSub(nameChanged, NSString*) // one arguments + + /* + NOT supported yet (but would be cool) + PubSub(multipleArgsCommand, NSString*, BOOL, NSString*) // multiple arguments... + */ + This generates two strongly typed methods that look kinda like this: @interface Pub + + (void) somethingHappened; + (void) nameChanged:(NSString*)arg; @end @interface Sub + + (void) while:(id)obj somethingHappened:(void(^)(void))callback; + (void) while:(id)obj nameChanged:(void(^)(NSString*))callback; @end From 4e3e8e438110a3d9f02446c61caa1d3351d732a5 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Mon, 24 Feb 2014 10:22:36 -0800 Subject: [PATCH 04/15] initial cocoapod podfile --- LICENSE.md | 20 +++++++++++++++++++ PubSub.m | 2 -- PubSub.podspec | 16 +++++++++++++++ .../TestPubSub.xcodeproj/project.pbxproj | 5 +++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 LICENSE.md create mode 100644 PubSub.podspec diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ff553dd --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jason Jarrett + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/PubSub.m b/PubSub.m index b518309..e16f00d 100644 --- a/PubSub.m +++ b/PubSub.m @@ -11,8 +11,6 @@ // #import "PubSub.h" -#import -#import #import diff --git a/PubSub.podspec b/PubSub.podspec new file mode 100644 index 0000000..f87d6a7 --- /dev/null +++ b/PubSub.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + + s.name = "PubSub" + s.version = "0.0.1" + s.summary = "A minimal syntax block based wrapper around NSNotificaitonCenter." + s.homepage = "https://github.com/staxmanade/PubSub-iOS" + s.license = { :type => 'MIT', :file => 'LICENSE.md' } + s.author = { "Jason Jarrett" => "jason@elegantcode.com" } + s.authors = { "Josh Wright" => "josh@joshwright.com", "Jason Jarrett" => "jason@elegantcode.com"} + s.platform = :ios + s.ios.deployment_target = "5.0" + s.source = { :git => "https://github.com/staxmanade/PubSub-iOS.git", :tag => "0.0.1" } + s.source_files = 'PubSub.h', 'PubSub.m' + s.requires_arc = true + +end diff --git a/TestProject/TestPubSub/TestPubSub.xcodeproj/project.pbxproj b/TestProject/TestPubSub/TestPubSub.xcodeproj/project.pbxproj index 312109a..3970039 100644 --- a/TestProject/TestPubSub/TestPubSub.xcodeproj/project.pbxproj +++ b/TestProject/TestPubSub/TestPubSub.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 58ABB18418BBC79000A2F782 /* PubSub.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 58ABB18318BBC79000A2F782 /* PubSub.podspec */; }; BC23B537175E6CB800577890 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC23B536175E6CB800577890 /* UIKit.framework */; }; BC23B539175E6CB800577890 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC23B538175E6CB800577890 /* Foundation.framework */; }; BC23B53B175E6CB800577890 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC23B53A175E6CB800577890 /* CoreGraphics.framework */; }; @@ -18,6 +19,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 58ABB18318BBC79000A2F782 /* PubSub.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PubSub.podspec; path = ../../PubSub.podspec; sourceTree = ""; }; BC23B532175E6CB800577890 /* TestPubSub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestPubSub.app; sourceTree = BUILT_PRODUCTS_DIR; }; BC23B536175E6CB800577890 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; BC23B538175E6CB800577890 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -51,6 +53,7 @@ BC23B527175E6CB800577890 = { isa = PBXGroup; children = ( + 58ABB18318BBC79000A2F782 /* PubSub.podspec */, BC23B562175EB67200577890 /* readme.md */, BC23B53C175E6CB800577890 /* TestPubSub */, BC23B535175E6CB800577890 /* Frameworks */, @@ -159,6 +162,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 58ABB18418BBC79000A2F782 /* PubSub.podspec in Resources */, BC23B541175E6CB800577890 /* InfoPlist.strings in Resources */, BC23B563175EB67200577890 /* readme.md in Resources */, ); @@ -281,6 +285,7 @@ BC23B552175E6CB800577890 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; From d1999988e08135c8140a7a81051585dba4657797 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Mon, 24 Feb 2014 13:09:57 -0800 Subject: [PATCH 05/15] fixed a bug where for zero args --- PubSub.m | 11 +++++++++-- TestProject/TestPubSub/TestPubSub/AppDelegate.m | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/PubSub.m b/PubSub.m index e16f00d..910a8b8 100644 --- a/PubSub.m +++ b/PubSub.m @@ -75,9 +75,16 @@ + (NSMethodSignature *) methodSignatureForSelector:(SEL)selector + (void)forwardInvocation:(NSInvocation *)i { id arg = nil; - [i getArgument:&arg atIndex:2]; - NSString* notificationName = [NSStringFromSelector(i.selector) componentsSeparatedByString:@":"][0]; + NSString *selectorName = NSStringFromSelector(i.selector); + NSArray *selectorArgs = [selectorName componentsSeparatedByString:@":"]; + + NSString* notificationName = selectorArgs[0]; + + if(selectorArgs.count > 1){ + [i getArgument:&arg atIndex:2]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:arg]; } diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index 3bd5d1c..9744ee8 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -34,6 +34,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [Sub while:keeper testWithZeroArgs:^{ NSLog(@"sub fired with zero args"); }]; + + [Pub testWithZeroArgs]; + [Pub testWithZeroArgs]; + [Pub testWithZeroArgs]; [Pub testWithZeroArgs]; [self performSelector:@selector(b) withObject:nil afterDelay:.1]; From 324a310d01c4ecee01e3031a3a4435c7775d7701 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Thu, 27 Feb 2014 13:58:03 -0800 Subject: [PATCH 06/15] removed un-necessary return statement --- PubSub.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/PubSub.m b/PubSub.m index 910a8b8..195640c 100644 --- a/PubSub.m +++ b/PubSub.m @@ -25,8 +25,6 @@ + (NSMethodSignature *) methodSignatureForSelector:(SEL)selector signature = [self methodSignatureForSelector:@selector(mockSubscribeWhile:callback:)]; } return signature; - - return nil; } + (void) forwardInvocation:(NSInvocation *)anInvocation From 91b29ecaf26301558b4bfd6048e48010f6a1b90d Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Mon, 3 Mar 2014 15:54:32 -0800 Subject: [PATCH 07/15] added support for up to three arguments and named parameter arguments --- PubSub.h | 42 +++++++++++- PubSub.m | 67 ++++++++++++++++--- .../TestPubSub/TestPubSub/AppDelegate.m | 63 +++++++++-------- .../TestPubSub/TestPubSub/Notifications.h | 12 +++- 4 files changed, 141 insertions(+), 43 deletions(-) diff --git a/PubSub.h b/PubSub.h index d58d8ed..5c930df 100644 --- a/PubSub.h +++ b/PubSub.h @@ -23,7 +23,7 @@ // Variable expansion with variable arguments thanks to // http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments - +/* #define PubSubWithZeroArgs(name) \ @interface Pub (PubSub_ ## name ## _Category) \ + (void) name; \ @@ -50,4 +50,42 @@ #define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__) #define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__) -#define PubSub(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__) \ No newline at end of file +#define PubSub(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__) +*/ + + +#define PubSub0Arg(name) \ +@interface Pub (PubSub_ ## name ## _Category) \ ++ (void) name; \ +@end\ +@interface Sub (PubSub_ ## name ## _Category)\ ++ (void) while:(id)obj name:(void(^)(void))callback;\ +@end + +#define PubSub1Arg(name, arg1Type, arg1Name) \ +@interface Pub (PubSub_ ## name ## _Category) \ ++ (void) name:(arg1Type)arg1Name; \ +@end\ +@interface Sub (PubSub_ ## name ## _Category)\ ++ (void) while:(id)obj name:(void(^)(arg1Type arg1Name))callback;\ +@end + +#define PubSub2Arg(name, arg1Type, arg1Name, arg2Type, arg2Name) \ +@interface Pub (PubSub_ ## name ## _Category) \ ++ (void) name:(arg1Type)arg1Name arg2Name:(arg2Type)arg2Name; \ +@end\ +@interface Sub (PubSub_ ## name ## _Category)\ ++ (void) while:(id)obj name:(void(^)(arg1Type arg1Name, arg2Type arg2Name))callback;\ +@end + + +#define PubSub3Arg(name, arg1Type, arg1Name, arg2Type, arg2Name, arg3Type, arg3Name) \ +@interface Pub (PubSub_ ## name ## _Category) \ ++ (void) name:(arg1Type)arg1Name arg2Name:(arg2Type)arg2Name arg3Name:(arg3Type)arg3Name; \ +@end\ +@interface Sub (PubSub_ ## name ## _Category)\ ++ (void) while:(id)obj name:(void(^)(arg1Type arg1Name, arg2Type arg2Name, arg3Type arg3Name))callback;\ +@end + + + diff --git a/PubSub.m b/PubSub.m index 195640c..e1cd217 100644 --- a/PubSub.m +++ b/PubSub.m @@ -34,8 +34,14 @@ + (void) forwardInvocation:(NSInvocation *)anInvocation __unsafe_unretained id keepAlive = nil; [anInvocation getArgument:&keepAlive atIndex:2]; - void(^callback)(id arg) = nil; - [anInvocation getArgument:&callback atIndex:3]; + void(^callbackZero)(void) = nil; + void(^callbackOne)(id arg1) = nil; + void(^callbackTwo)(id arg1, id arg2) = nil; + void(^callbackThree)(id arg1, id arg2, id arg3) = nil; + [anInvocation getArgument:&callbackZero atIndex:3]; + [anInvocation getArgument:&callbackOne atIndex:3]; + [anInvocation getArgument:&callbackTwo atIndex:3]; + [anInvocation getArgument:&callbackThree atIndex:3]; NSString* notificationName = [NSStringFromSelector(aSelector) componentsSeparatedByString:@":"][1]; @@ -48,7 +54,26 @@ + (void) forwardInvocation:(NSInvocation *)anInvocation return; } - callback(notification.object); + if(notification.userInfo.count == 0){ + callbackZero(); + return; + } + + if(notification.userInfo.count == 1){ + callbackOne(notification.userInfo[@"0"]); + return; + } + + if(notification.userInfo.count == 2){ + callbackTwo(notification.userInfo[@"0"], notification.userInfo[@"1"]); + return; + } + + if(notification.userInfo.count == 3){ + callbackThree(notification.userInfo[@"0"], notification.userInfo[@"1"], notification.userInfo[@"2"]); + return; + } + }]; } @@ -58,32 +83,52 @@ + (void) forwardInvocation:(NSInvocation *)anInvocation @implementation Pub -+ (void) mockPublish:(id)arg { } ++ (void) mockPublishZero { } ++ (void) mockPublishOne:(id)arg1 { } ++ (void) mockPublishTwo:(id)arg1 :(id)arg2 { } ++ (void) mockPublishThree:(id)arg1 :(id)arg2 :(id)arg3 { } + (NSMethodSignature *) methodSignatureForSelector:(SEL)selector { + NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { - signature = [self methodSignatureForSelector:@selector(mockPublish:)]; + NSString *selectorName = NSStringFromSelector(selector); + NSArray *selectorArgs = [selectorName componentsSeparatedByString:@":"]; + int argCount = selectorArgs.count - 1; + if(argCount == 0) { + signature = [self methodSignatureForSelector:@selector(mockPublishZero)]; + } else if(argCount == 1) { + signature = [self methodSignatureForSelector:@selector(mockPublishOne:)]; + } else if(argCount == 2) { + signature = [self methodSignatureForSelector:@selector(mockPublishTwo::)]; + } else if(argCount == 3) { + signature = [self methodSignatureForSelector:@selector(mockPublishThree:::)]; + } } return signature; } -+ (void)forwardInvocation:(NSInvocation *)i ++ (void)forwardInvocation:(NSInvocation *)anInvocation { - id arg = nil; - NSString *selectorName = NSStringFromSelector(i.selector); + NSString *selectorName = NSStringFromSelector(anInvocation.selector); NSArray *selectorArgs = [selectorName componentsSeparatedByString:@":"]; NSString* notificationName = selectorArgs[0]; - if(selectorArgs.count > 1){ - [i getArgument:&arg atIndex:2]; + NSMutableDictionary *argsDict = [NSMutableDictionary new]; + + for (NSUInteger i = 0; i < (selectorArgs.count-1); i++) { + id arg = nil; + NSInteger paramIndex = i+2; + [anInvocation getArgument:&arg atIndex:paramIndex]; + + [argsDict setObject:arg forKey:[[NSNumber numberWithInt:i] stringValue]]; } - [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:arg]; + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil userInfo:argsDict]; } @end diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index 9744ee8..a6bbad3 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -23,46 +23,53 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self.window makeKeyAndVisible]; keeper = [[NSObject alloc] init]; - - [Sub while:keeper nicknameChanged:^(NSString* newNickname) { - NSLog(@"nickname changed to: %@", newNickname); - }]; - - [Pub nicknameChanged:@"A"]; + // + // Zero arg subscription + // [Sub while:keeper testWithZeroArgs:^{ - NSLog(@"sub fired with zero args"); + NSLog(@"Zero args..."); }]; [Pub testWithZeroArgs]; [Pub testWithZeroArgs]; [Pub testWithZeroArgs]; [Pub testWithZeroArgs]; + + // + // One arg subscription + // + [Sub while:keeper testWithOneArg:^(NSString *a) { + NSLog(@"One arg: %@", a); + }]; - [self performSelector:@selector(b) withObject:nil afterDelay:.1]; - [self performSelector:@selector(c) withObject:nil afterDelay:.15]; - [self performSelector:@selector(d) withObject:nil afterDelay:.2]; + [Pub testWithOneArg:@"A"]; - return YES; -} - -- (void) b -{ - NSLog(@"publishing b"); - [Pub nicknameChanged:@"B"]; -} - -- (void) c -{ - NSLog(@"keeper = nil"); - keeper = nil; -} + + // + // Two arg subscription + // + [Sub while:keeper testWithTwoArgs:^(NSString *a, NSString *b) { + NSLog(@"Two args: a: %@, b: %@", a, b); + }]; + [Pub testWithTwoArgs:@"a" b:@"B"]; + [Pub testWithTwoArgs:@"A" b:@"b"]; + [Pub testWithTwoArgs:@"aaa" b:@"bbb"]; + + // + // Three arg subscription + // + [Sub while:keeper testWithThreeArgs:^(NSString *a, NSString *b, NSString *c) { + NSLog(@"Three args: a: %@, b: %@, c: %@", a, b, c); + }]; + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; -- (void) d -{ - NSLog(@"publishing d"); - [Pub nicknameChanged:@"D"]; + return YES; } @end diff --git a/TestProject/TestPubSub/TestPubSub/Notifications.h b/TestProject/TestPubSub/TestPubSub/Notifications.h index 9b373ae..82787cf 100644 --- a/TestProject/TestPubSub/TestPubSub/Notifications.h +++ b/TestProject/TestPubSub/TestPubSub/Notifications.h @@ -9,7 +9,15 @@ #import #import "PubSub.h" -PubSub(nicknameChanged, NSString*) +PubSub0Arg(testWithZeroArgs) + +PubSub1Arg(testWithOneArg, \ + NSString*, a) + +PubSub2Arg(testWithTwoArgs, \ + NSString*, a, \ + NSString*, b) + +PubSub3Arg(testWithThreeArgs, NSString*, a, NSString*, b, NSString *, c) -PubSub(testWithZeroArgs) From 3ce714bbf767804d5e5396ca3511bac4eef44f90 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Tue, 4 Mar 2014 08:55:13 -0800 Subject: [PATCH 08/15] api cleanup and documentation updates --- PubSub.h | 38 +------- .../TestPubSub/TestPubSub/AppDelegate.m | 1 - .../TestPubSub/TestPubSub/Notifications.h | 19 ++-- readme.md | 92 ++++++++++++------- 4 files changed, 76 insertions(+), 74 deletions(-) diff --git a/PubSub.h b/PubSub.h index 5c930df..6bbb877 100644 --- a/PubSub.h +++ b/PubSub.h @@ -23,38 +23,10 @@ // Variable expansion with variable arguments thanks to // http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments -/* -#define PubSubWithZeroArgs(name) \ -@interface Pub (PubSub_ ## name ## _Category) \ -+ (void) name; \ -@end\ -@interface Sub (PubSub_ ## name ## _Category)\ -+ (void) while:(id)obj name:(void(^)(void))callback;\ -@end - -#define PubSubWithOneArg(name, type) \ -@interface Pub (PubSub_ ## name ## _Category) \ -+ (void) name:(type)arg; \ -@end\ -@interface Sub (PubSub_ ## name ## _Category)\ -+ (void) while:(id)obj name:(void(^)(type))callback;\ -@end - - -#define _ARG2(_0, _1, _2, ...) _2 -#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0) - -#define _ONE_OR_TWO_ARGS_1(a) PubSubWithZeroArgs(a) -#define _ONE_OR_TWO_ARGS_2(a, b) PubSubWithOneArg(a,b) - -#define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__) -#define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__) - -#define PubSub(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__) -*/ +// TODO look at a generic PubSub(name, ...) macro? -#define PubSub0Arg(name) \ +#define PubSub0(name) \ @interface Pub (PubSub_ ## name ## _Category) \ + (void) name; \ @end\ @@ -62,7 +34,7 @@ + (void) while:(id)obj name:(void(^)(void))callback;\ @end -#define PubSub1Arg(name, arg1Type, arg1Name) \ +#define PubSub1(name, arg1Type, arg1Name) \ @interface Pub (PubSub_ ## name ## _Category) \ + (void) name:(arg1Type)arg1Name; \ @end\ @@ -70,7 +42,7 @@ + (void) while:(id)obj name:(void(^)(arg1Type arg1Name))callback;\ @end -#define PubSub2Arg(name, arg1Type, arg1Name, arg2Type, arg2Name) \ +#define PubSub2(name, arg1Type, arg1Name, arg2Type, arg2Name) \ @interface Pub (PubSub_ ## name ## _Category) \ + (void) name:(arg1Type)arg1Name arg2Name:(arg2Type)arg2Name; \ @end\ @@ -79,7 +51,7 @@ @end -#define PubSub3Arg(name, arg1Type, arg1Name, arg2Type, arg2Name, arg3Type, arg3Name) \ +#define PubSub3(name, arg1Type, arg1Name, arg2Type, arg2Name, arg3Type, arg3Name) \ @interface Pub (PubSub_ ## name ## _Category) \ + (void) name:(arg1Type)arg1Name arg2Name:(arg2Type)arg2Name arg3Name:(arg3Type)arg3Name; \ @end\ diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index a6bbad3..2b31610 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -24,7 +24,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( keeper = [[NSObject alloc] init]; - // // Zero arg subscription // diff --git a/TestProject/TestPubSub/TestPubSub/Notifications.h b/TestProject/TestPubSub/TestPubSub/Notifications.h index 82787cf..5794077 100644 --- a/TestProject/TestPubSub/TestPubSub/Notifications.h +++ b/TestProject/TestPubSub/TestPubSub/Notifications.h @@ -10,14 +10,19 @@ #import "PubSub.h" -PubSub0Arg(testWithZeroArgs) +PubSub0(testWithZeroArgs) -PubSub1Arg(testWithOneArg, \ - NSString*, a) +PubSub1(testWithOneArg, \ + NSString*, a) + +PubSub2(testWithTwoArgs, \ + NSString*, a, \ + NSString*, b) + +PubSub3(testWithThreeArgs, \ + NSString*, a, \ + NSString*, b, \ + NSString*, c) -PubSub2Arg(testWithTwoArgs, \ - NSString*, a, \ - NSString*, b) -PubSub3Arg(testWithThreeArgs, NSString*, a, NSString*, b, NSString *, c) diff --git a/readme.md b/readme.md index 611a606..3bbace4 100644 --- a/readme.md +++ b/readme.md @@ -10,10 +10,10 @@ The goal is minimal syntax, strong typing, and automatic unregistering. Here's what it looks like: // Declare your notification - PubSub(nameChanged, NSString) + PubSub1(nameChanged, NSString *name) // Subscribe - [Sub while:self nameChanged:^(NSString* name){ + [Sub while:self nameChanged:^(NSString *name){ NSLog(@"New Name: %@", name); }]; @@ -26,14 +26,23 @@ Here's what it looks like: This library has no dependencies and requires arc. -### Copy 3 Files +### Install into your project + +#### Option 1 (Copy 3 files) Copy `PubSub.h`, `PubSub.m`, and `Notifications.h` into your XCode project. The PubSub files do all the work and `Notifications.h` is where you declare your notifications. If your project doesn't have ARC enabled, add the `-fobjc-arc` flag for `PubSub.m`. -### Import Notifications.h +#### Option 2 (Installation with CocoaPods) + +CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries. + + pod "PubSub" + + +### Import Notifications.h (Bonus step) In your `AppName-Prefix.pch` file, add `#import "Notifications.h"`. This makes it available in all your classes. You can skip this step if you want to do it differently. @@ -42,43 +51,71 @@ in all your classes. You can skip this step if you want to do it differently. In `Notifications.h` you will use a preprocessor statement to declare your notifications. Declare one per line. For example: - PubSub(somethingHappened) // zero arguments + PubSub0(testWithZeroArgs) + + PubSub1(testWithOneArg, \ + NSString*, a) + + PubSub2(testWithTwoArgs, \ + NSString*, a, \ + NSString*, b) - PubSub(nameChanged, NSString*) // one arguments + PubSub3(testWithThreeArgs, \ + NSString*, a, \ + NSString*, b, \ + NSString*, c) - /* - NOT supported yet (but would be cool) - PubSub(multipleArgsCommand, NSString*, BOOL, NSString*) // multiple arguments... - */ +The first argument to `PubZubN` is the name of the notification/event. For each parameter you specify the `type` and the `name` of the argument up to 3 arguments. -This generates two strongly typed methods that look kinda like this: +These macro's generate the below strongly typed interface definition methods: @interface Pub - + (void) somethingHappened; - + (void) nameChanged:(NSString*)arg; + + (void) testWithZeroArgs; + + (void) testWithOneArg:(NSString*)a; + + (void) testWithTwoArgs:(NSString*)a b:(NSString*)b; + + (void) testWithThreeArgs:(NSString*)a b:(NSString*)b c:(NSString*)c; @end + @interface Sub - + (void) while:(id)obj somethingHappened:(void(^)(void))callback; - + (void) while:(id)obj nameChanged:(void(^)(NSString*))callback; + + (void) while:(id)obj testWithZeroArgs:(void(^)(void))callback; + + (void) while:(id)obj testWithOneArg:(void(^)(NSString *a))callback; + + (void) while:(id)obj testWithTwoArgs:(void(^)(NSString *a, NSString *b))callback; + + (void) while:(id)obj testWithThreeArgs:(void(^)(NSString *a, NSString *b, NSString *c))callback; @end -The first argument to `PubSub` is the name - it can be anything you want. The second argument -is the type of object you are sending out. - + ### Publishing -Now whenever you want to post a `nameChanged` notification, you just call: +Now whenever you want to post a notification, you can call: - [Pub nameChanged:@"Josh"]; + [Pub testWithZeroArgs]; + [Pub testWithOneArg:@"a"]; + [Pub testWithTwoArgs:@"a" b:@"b"]; + + [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + + ### Subscribing When you want to subscribe to an event, you pass it the block of code that should run: - [Sub while:self nameChanged:^(NSString* name){ - NSLog(@"New Name: %@", name); + [Sub while:self testWithZeroArgs:^{ + NSLog(@"zero args notification published"); + }]; + + [Sub while:self testWithOneArg:^(NSString* a){ + NSLog(@"a:%@", a); + }]; + + [Sub while:self testWithTwoArgs:^(NSString *a, NSString *b){ + NSLog(@"a:%@ b:%@", a, b); + }]; + + [Sub while:self testWithThreeArgs:^(NSString *a, NSString *b, NSString *c){ + NSLog(@"a:%@ b:%@ c:%@", a, b, c); }]; The first argument `while` is the best part. It keeps a weak reference to an object. When @@ -91,14 +128,3 @@ unsubscribed. No cleanup necessary. Compare that to `NSNotificationCenter` where you have to retain an observer then you have to explicitly unregister when you're done. - - - - - - - - - - - From 88407041e534f690975f675a1eac3d39fd38841f Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Thu, 6 Mar 2014 12:37:57 -0800 Subject: [PATCH 09/15] adding support for automatically handling nil values --- PubSub.m | 19 ++++++++++++--- .../TestPubSub/TestPubSub/AppDelegate.m | 24 +++++++++++++++++++ .../TestPubSub/TestPubSub/Notifications.h | 11 +++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/PubSub.m b/PubSub.m index e1cd217..d7bcb16 100644 --- a/PubSub.m +++ b/PubSub.m @@ -59,18 +59,27 @@ + (void) forwardInvocation:(NSInvocation *)anInvocation return; } + __block id (^getArgAtIndex)(NSString *) = ^id(NSString *index) { + id result = notification.userInfo[index]; + if(result == [NSNull null]){ + return nil; + } + return result; + }; + + if(notification.userInfo.count == 1){ - callbackOne(notification.userInfo[@"0"]); + callbackOne(getArgAtIndex(@"0")); return; } if(notification.userInfo.count == 2){ - callbackTwo(notification.userInfo[@"0"], notification.userInfo[@"1"]); + callbackTwo(getArgAtIndex(@"0"), getArgAtIndex(@"1")); return; } if(notification.userInfo.count == 3){ - callbackThree(notification.userInfo[@"0"], notification.userInfo[@"1"], notification.userInfo[@"2"]); + callbackThree(getArgAtIndex(@"0"), getArgAtIndex(@"1"), getArgAtIndex(@"2")); return; } @@ -125,6 +134,10 @@ + (void)forwardInvocation:(NSInvocation *)anInvocation NSInteger paramIndex = i+2; [anInvocation getArgument:&arg atIndex:paramIndex]; + if(arg == nil){ + arg = [NSNull null]; + } + [argsDict setObject:arg forKey:[[NSNumber numberWithInt:i] stringValue]]; } diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index 2b31610..b8c0d24 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -67,8 +67,32 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; [Pub testWithThreeArgs:@"a" b:@"b" c:@"c"]; + + + [self testEventWithNilArguments]; return YES; } + +- (void) testEventWithNilArguments { + [Sub while:self testWith1NilArguments:^(NSString *a) { + NSParameterAssert(a == nil); + }]; + [Pub testWith1NilArguments:nil]; + + [Sub while:self testWith2NilArguments:^(NSString *a, NSString *b) { + NSParameterAssert(a == nil); + NSParameterAssert(b == nil); + }]; + [Pub testWith2NilArguments:nil b:nil]; + + [Sub while:self testWith3NilArguments:^(NSString *a, NSString *b, NSString *c) { + NSParameterAssert(a == nil); + NSParameterAssert(b == nil); + NSParameterAssert(c == nil); + }]; + [Pub testWith3NilArguments:nil b:nil c:nil]; +} + @end diff --git a/TestProject/TestPubSub/TestPubSub/Notifications.h b/TestProject/TestPubSub/TestPubSub/Notifications.h index 5794077..1872351 100644 --- a/TestProject/TestPubSub/TestPubSub/Notifications.h +++ b/TestProject/TestPubSub/TestPubSub/Notifications.h @@ -26,3 +26,14 @@ PubSub3(testWithThreeArgs, \ +PubSub1(testWith1NilArguments, \ + NSString*, a) + +PubSub2(testWith2NilArguments, \ + NSString*, a, \ + NSString*, b) + +PubSub3(testWith3NilArguments, \ + NSString*, a, \ + NSString*, b, \ + NSString*, c) \ No newline at end of file From 0cdf0f7e7994e0da2e9c62648d471bf46c97096f Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Fri, 7 Mar 2014 10:26:47 -0800 Subject: [PATCH 10/15] Update readme.md --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 3bbace4..066873d 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,5 @@ - ## PubSub-iOS PubSub-iOS is a very simple, block based wrapper around `NSNotificationCenter`. @@ -10,7 +9,7 @@ The goal is minimal syntax, strong typing, and automatic unregistering. Here's what it looks like: // Declare your notification - PubSub1(nameChanged, NSString *name) + PubSub1(nameChanged, NSString*, name) // Subscribe [Sub while:self nameChanged:^(NSString *name){ From 69d971813cf862dd15bb3fab435506b5f527006a Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Fri, 7 Mar 2014 13:56:08 -0800 Subject: [PATCH 11/15] Update readme.md --- readme.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 066873d..467f17e 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,4 @@ - ## PubSub-iOS PubSub-iOS is a very simple, block based wrapper around `NSNotificationCenter`. @@ -127,3 +126,7 @@ unsubscribed. No cleanup necessary. Compare that to `NSNotificationCenter` where you have to retain an observer then you have to explicitly unregister when you're done. + +# WARNING: + +You can't use value types such as `int`, `BOOL`, etc in the PubSub macro... _If someone could help me figure out a way to acomplish this (possibly through some macro tricks) I'd love the feedback!_ From 514da90a6f3adbae284d0b6f8de5a2175020ac39 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Fri, 7 Mar 2014 13:59:13 -0800 Subject: [PATCH 12/15] Update readme.md --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 467f17e..06d6e54 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,8 @@ +_NOTE: this project is a fork of [bendytree/PubSub-iOS](https://github.com/bendytree/PubSub-iOS) and has changed significantly from it's original source. I'd like to say thanks to *bendytree* for the idea and the kick-start of a project._ + + + ## PubSub-iOS PubSub-iOS is a very simple, block based wrapper around `NSNotificationCenter`. From 4badf2cd3d57856e152f683c7a6156c1c0adb357 Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Fri, 7 Mar 2014 14:00:55 -0800 Subject: [PATCH 13/15] adding a sample of a scenario I would like to see supported --- TestProject/TestPubSub/TestPubSub/AppDelegate.m | 9 +++++++++ TestProject/TestPubSub/TestPubSub/Notifications.h | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/TestProject/TestPubSub/TestPubSub/AppDelegate.m b/TestProject/TestPubSub/TestPubSub/AppDelegate.m index b8c0d24..2d62088 100644 --- a/TestProject/TestPubSub/TestPubSub/AppDelegate.m +++ b/TestProject/TestPubSub/TestPubSub/AppDelegate.m @@ -70,6 +70,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self testEventWithNilArguments]; + [self testWithAnInt]; return YES; } @@ -95,4 +96,12 @@ - (void) testEventWithNilArguments { [Pub testWith3NilArguments:nil b:nil c:nil]; } +- (void) testWithAnInt { +// TODO: find a way to support this scenario +// [Sub while:self testWithAnInt:^(int a) { +// NSParameterAssert(a == 7); +// }]; +// [Pub testWithAnInt:7]; +} + @end diff --git a/TestProject/TestPubSub/TestPubSub/Notifications.h b/TestProject/TestPubSub/TestPubSub/Notifications.h index 1872351..e7ff375 100644 --- a/TestProject/TestPubSub/TestPubSub/Notifications.h +++ b/TestProject/TestPubSub/TestPubSub/Notifications.h @@ -36,4 +36,8 @@ PubSub2(testWith2NilArguments, \ PubSub3(testWith3NilArguments, \ NSString*, a, \ NSString*, b, \ - NSString*, c) \ No newline at end of file + NSString*, c) + + +// TODO: find a way to support this scenario +// PubSub1(testWithAnInt, int, a) \ No newline at end of file From bf09881cb514cfb84c7d2feb978e39d0068e10de Mon Sep 17 00:00:00 2001 From: Jason Jarrett Date: Tue, 8 Apr 2014 09:04:35 -0700 Subject: [PATCH 14/15] Update readme.md --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 06d6e54..39783bb 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,8 @@ - _NOTE: this project is a fork of [bendytree/PubSub-iOS](https://github.com/bendytree/PubSub-iOS) and has changed significantly from it's original source. I'd like to say thanks to *bendytree* for the idea and the kick-start of a project._ +# WARNING: +I love the concept of this project and the simplicity of declaring, consuming and publishing of notifications it provides. However, I've recently pulled it out of a project I was using due to a number of random crashes - if anyone more Objective-C versed than I could have a look I'd love some feedback. But for now - BEWARE :P + ## PubSub-iOS From 970bb5f5484834bcefbdb3e11f720394e8582cfd Mon Sep 17 00:00:00 2001 From: ReadmeCritic Date: Wed, 17 Feb 2016 07:41:27 -0800 Subject: [PATCH 15/15] Correct the capitalization of Xcode in README --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 39783bb..84a7066 100644 --- a/readme.md +++ b/readme.md @@ -34,7 +34,7 @@ This library has no dependencies and requires arc. #### Option 1 (Copy 3 files) -Copy `PubSub.h`, `PubSub.m`, and `Notifications.h` into your XCode project. The PubSub files +Copy `PubSub.h`, `PubSub.m`, and `Notifications.h` into your Xcode project. The PubSub files do all the work and `Notifications.h` is where you declare your notifications. If your project doesn't have ARC enabled, add the `-fobjc-arc` flag for `PubSub.m`.