Permalink
Browse files

Full source code documentation.

Signed-off-by: Zachary Waldowski <zwaldowski@gmail.com>
  • Loading branch information...
1 parent b20aef4 commit f578e3718017dca1f9307cbad93501c2528e2d25 @zwaldowski zwaldowski committed Mar 28, 2012
Showing with 239 additions and 9 deletions.
  1. +86 −3 A2BlockDelegate.h
  2. +153 −6 A2DynamicDelegate.h
View
@@ -8,21 +8,104 @@
#import <Foundation/Foundation.h>
+/** The A2BlockDelegate category extends features provided
+ by A2DynamicDelegate to create custom block properties in
+ a category on a delegating object and dynamically map them
+ to delegate (`UIAlertViewDelegate`),
+ data source (`UITableViewDataSource`), or other delegated
+ protocol (`NSErrorRecoveryAttempting`) methods.
+
+ Simply call one of the methods in the category on a class
+ to add a block property to that class.
+
+ These methods should be called in a category's `+load` method,
+ before the application starts.
+ */
@interface NSObject (A2BlockDelegate)
-#pragma mark - Data Source
+/** @name Data Source Properties */
+/** Synthesizes a property with the given name and
+ links it to the given selector in the data source
+ protocol.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDataSource`
+ for instances of class `FooBar`. The method will generate
+ appropriate `setHandler:` and `handler` implementations for
+ the given property name.
+
+ @param propertyName A property name to synthesize. Must not be NULL.
+ @param selector An encoded selector. Must not be NULL.
+ */
+ (void) linkCategoryBlockProperty: (NSString *) propertyName withDataSourceMethod: (SEL) selector;
+
+/** Synthesizes multiple properties and links them to
+ the appropriate selector in the data source protocol.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDataSource`
+ for instances of class `FooBar`. The method will generate
+ appropriate `setHandler:` and `handler` implementations for
+ each property name and selector name string pair.
+
+ @param selectorsForPropertyNames A dictionary with property
+ names as keys and selectors (as strings) as objects.
+ */
+ (void) linkDataSourceMethods: (NSDictionary *) selectorsForPropertyNames;
-#pragma mark - Delegate
+/** @name Delegate Properties */
+/** Synthesizes a property with the given name and
+ links it to the given selector in the delegate protocol.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDelegate`
+ for instances of class `FooBar`. The method will generate
+ appropriate `setHandler:` and `handler` implementations for
+ the given property name.
+
+ @param propertyName A property name to synthesize. Must not be NULL.
+ @param selector An encoded selector. Must not be NULL.
+ */
+ (void) linkCategoryBlockProperty: (NSString *) propertyName withDelegateMethod: (SEL) selector;
+
+/** Synthesizes multiple properties and links them to
+ the appropriate selector in the delegate protocol.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDelegate`
+ for instances of class `FooBar`. The method will generate
+ appropriate `setHandler:` and `handler` implementations for
+ each property name and selector name string pair.
+
+ @param selectorsForPropertyNames A dictionary with property
+ names as keys and selectors (as strings) as objects.
+ */
+ (void) linkDelegateMethods: (NSDictionary *) selectorsForPropertyNames;
-#pragma mark - Other Protocol
+/** @name Other Protocol Properties */
+/** Synthesizes a property with the given name and
+ links it to the given selector in the given protocol.
+
+ The method will generate appropriate `setHandler:`
+ and `handler` implementations for the given property name.
+
+ @param propertyName A property name to synthesize. Must not be NULL.
+ @param protocol A protocol that declares the given selector. Must not be NULL.
+ @param selector An encoded selector. Must not be NULL.
+ */
+ (void) linkCategoryBlockProperty: (NSString *) propertyName withProtocol: (Protocol *) protocol method: (SEL) selector;
+
+/** Synthesizes multiple properties and links them to
+ the appropriate selector in the given protocol.
+
+ The method will generate appropriate `setHandler:`
+ and `handler` implementations for each property name and
+ selector name string pair.
+
+ @param protocol A protocol that declares all of the given
+ selectors. Must not be NULL.
+ @param selectorsForPropertyNames A dictionary with property
+ names as keys and selectors (as strings) as objects.
+ */
+ (void) linkProtocol: (Protocol *) protocol methods: (NSDictionary *) selectorsForPropertyNames;
@end
View
@@ -8,38 +8,185 @@
#import <Foundation/Foundation.h>
+/** A2DynamicDelegate implements a class's delegate,
+ data source, or other delegated protocol by associating
+ protocol methods with a block implementations.
+
+ - (IBAction) annoyUser
+ {
+ // Create an alert view
+ UIAlertView *alertView = [[UIAlertView alloc]
+ initWithTitle: @"Hello World!"
+ message: @"This alert's delegate is implemented using blocks. That's so cool!"
+ delegate: nil
+ cancelButtonTitle: @"Meh."
+ otherButtonTitles: @"Woo!", nil];
+
+ // Get the dynamic delegate
+ A2DynamicDelegate *dd = alertView.dynamicDelegate;
+
+ // Implement -alertViewShouldEnableFirstOtherButton:
+ [dd implementMethod: @selector(alertViewShouldEnableFirstOtherButton:) withBlock: ^(UIAlertView *alertView) {
+ NSLog(@"Message: %@", alertView.message);
+ return YES;
+ }];
+
+ // Implement -alertView:willDismissWithButtonIndex:
+ [dd implementMethod: @selector(alertView:willDismissWithButtonIndex:) withBlock: ^(UIAlertView *alertView, NSInteger buttonIndex) {
+ NSLog(@"You pushed button #%d (%@)", buttonIndex, [alertView buttonTitleAtIndex: buttonIndex]);
+ }];
+
+ // Set the delegate
+ alertView.delegate = dd;
+
+ [alertView show];
+ [alertView release];
+ }
+
+ A2DynamicDelegate is designed to be 'plug and play'. It just works. Pretty neat, huh?
+
+ @warning An A2DynamicDelegate cannot simply be allocated. Calling one of the
+ A2DynamicDelegate methods on NSObject, -dynamicDataSource, -dynamicDelegate,
+ or -dynamicDelegateForProtocol: allows us to store the dynamic delegate as
+ an associated object of the delegating object. This not only allows us to
+ later retrieve it, but it also creates a strong relationship. Since delegates
+ are usually weak references on the part of the delegating object, a dynamic
+ delegate would be deallocated immediately after its declaring scope ends.
+ */
@interface A2DynamicDelegate : NSObject {
NSMutableDictionary *_handlers;
}
-// Block objects *DO NOT* need to be copied before entering the dictionary.
+/** A dictionary of custom handlers to be used by custom responders
+ in a A2Dynamic(Protocol Name) subclass of A2DynamicDelegate, like
+ `A2DynamicUIAlertViewDelegate`. Block objects stored will be
+ automatically copied, and therefore *DO NOT* need to be copied
+ by the user.
+ */
@property (nonatomic, retain, readonly) NSMutableDictionary *handlers;
-#pragma mark - Block Class Method Implementations
+/** @name Block Class Method Implementations */
+/** The block that is to be fired when the specified
+ selector is called on the reciever.
+
+ @param selector An encoded selector. Must not be NULL.
+ @return A code block, or nil if no block is assigned.
+ */
- (id) blockImplementationForMethod: (SEL) selector;
+/** Assigns the given block to be fired when the specified
+ selector is called on the reciever.
+
+ [tableView.dynamicDataSource implementMethod:@selector(numberOfSectionsInTableView:)
+ withBlock:NSInteger^(UITableView *tableView){
+ return 2;
+ }];
+
+ @warning Starting with A2DynamicDelegate 2.0, a block will
+ not be checked for a matching signature. A block can have
+ less parameters than the original selector and will be
+ ignored, but cannot have more.
+
+ @param selector An encoded selector. Must not be NULL.
+ @param block A code block with the same signature as selector.
+ */
- (void) implementMethod: (SEL) selector withBlock: (id) block;
+
+/** Disassociates any block so that nothing will be fired
+ when the specified selector is called on the reciever.
+
+ @param selector An encoded selector. Must not be NULL.
+ */
- (void) removeBlockImplementationForMethod: (SEL) selector;
-#pragma mark - Block Instance Method Implementations
+/** @name Block Instance Method Implementations */
+/** The block that is to be fired when the specified
+ selector is called on the delegating object's class.
+
+ @param selector An encoded selector. Must not be NULL.
+ @return A code block, or nil if no block is assigned.
+ */
- (id) blockImplementationForClassMethod: (SEL) selector;
+/** Assigns the given block to be fired when the specified
+ selector is called on the reciever.
+
+ @warning Starting with A2DynamicDelegate 2.0, a block will
+ not be checked for a matching signature. A block can have
+ less parameters than the original selector and will be
+ ignored, but cannot have more.
+
+ @param selector An encoded selector. Must not be NULL.
+ @param block A code block with the same signature as selector.
+ */
- (void) implementClassMethod: (SEL) selector withBlock: (id) block;
+
+/** Disassociates any blocks so that nothing will be fired
+ when the specified selector is called on the delegating
+ object's class.
+
+ @param selector An encoded selector. Must not be NULL.
+ */
- (void) removeBlockImplementationForClassMethod: (SEL) selector;
@end
@interface NSObject (A2DynamicDelegate)
-// Assumes protocol name is "Class ## DataSource"
+/** Creates or gets a dynamic data source for the reciever.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDataSource`
+ for instances of class `FooBar`. The object is given a strong
+ attachment to the reciever, and is automatically deallocated
+ when the reciever is released.
+
+ If the user implements a `A2DynamicFooBarDataSource` subclass
+ of A2DynamicDelegate, its implementation of any method
+ will be used over the block. If the block needs to be used,
+ it can be called from within the custom
+ implementation using blockImplementationForMethod:.
+
+ @see blockImplementationForMethod:
+ @return A dynamic data source.
+ */
- (id) dynamicDataSource;
-// Assumes protocol name is "Class ## Delegate"
+/** Creates or gets a dynamic delegate for the reciever.
+
+ A2DynamicDelegate assumes a protocol name `FooBarDelegate`
+ for instances of class `FooBar`. The object is given a strong
+ attachment to the reciever, and is automatically deallocated
+ when the reciever is released.
+
+ If the user implements a `A2DynamicFooBarDelegate` subclass
+ of A2DynamicDelegate, its implementation of any method
+ will be used over the block. If the block needs to be used,
+ it can be called from within the custom
+ implementation using blockImplementationForMethod:.
+
+ @see blockImplementationForMethod:
+ @return A dynamic delegate.
+ */
- (id) dynamicDelegate;
-// Designated initializer
+/** Creates or gets a dynamic protocol implementation for
+ the reciever. The designated initializer.
+
+ The object is given a strong attachment to the reciever,
+ and is automatically deallocated when the reciever is released.
+
+ If the user implements a subclass of A2DynamicDelegate prepended
+ with `A2Dynamic`, such as `A2DynamicFooProvider`, its
+ implementation of any method will be used over the block.
+ If the block needs to be used, it can be called from within the
+ custom implementation using blockImplementationForMethod:.
+
+ @param protocol A custom protocol.
+ @return A dynamic protocol implementation.
+ @see blockImplementationForMethod:
+ */
- (id) dynamicDelegateForProtocol: (Protocol *) protocol;
@end

0 comments on commit f578e37

Please sign in to comment.