Skip to content

Commit

Permalink
Adds new methods that allow setting a custom accessoryView directly w…
Browse files Browse the repository at this point in the history
…hen mapping objects/classes with tableview cell actions
chriscox committed Jul 10, 2013
1 parent 19dd716 commit 94c3e69
Showing 4 changed files with 196 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/core/src/NIActions+Subclassing.h
Original file line number Diff line number Diff line change
@@ -34,5 +34,6 @@
@property (nonatomic, NI_WEAK) id target;

- (NIObjectActions *)actionForObjectOrClassOfObject:(id<NSObject>)object;
- (UIView *)accessoryViewForObjectOrClassOfObject:(id<NSObject>)object;

@end
108 changes: 108 additions & 0 deletions src/core/src/NIActions.h
Original file line number Diff line number Diff line change
@@ -71,6 +71,28 @@ NSArray *objects = @[
NSLog(@"Object was tapped: %@", object);
}];
@endcode
*
* <h3>Setting a Custom Accessory View</h3>
* For either tap block or selector invocations, there is an option to set a custom accessoryView.
*
* The following is an example of setting an accessoryView:
*
@code
UISwitch *switchControl = [[UISwitch alloc] init];
switchControl.tag = 1;
[switchControl addTarget:self action:@selector(switched:) forControlEvents:UIControlEventValueChanged];
NSArray *objects = @[
[NITitleCellObject objectWithTitle:@"Custom Accessory View"],
[self.actions attachToObject:[NITitleCellObject objectWithTitle:@"UISwitch Cell"]
accessoryView:switchControl
tapSelector:nil]
];
- (void)switched:(id)switchControl {
NSLog(@"Switch %i is now %@.", switchControl.tag, (switchControl.on) ? @"on" : @"off");
}
@endcode
*
*/
@interface NIActions : NSObject
@@ -83,24 +105,29 @@ NSArray *objects = @[
- (id)attachToObject:(id<NSObject>)object tapBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object detailBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object navigationBlock:(NIActionBlock)action;
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action;

- (id)attachToObject:(id<NSObject>)object tapSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object detailSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object navigationSelector:(SEL)selector;
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector;

#pragma mark Mapping Classes

- (void)attachToClass:(Class)aClass tapBlock:(NIActionBlock)action;
- (void)attachToClass:(Class)aClass detailBlock:(NIActionBlock)action;
- (void)attachToClass:(Class)aClass navigationBlock:(NIActionBlock)action;
- (void)attachToClass:(Class)aClass accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action;

- (void)attachToClass:(Class)aClass tapSelector:(SEL)selector;
- (void)attachToClass:(Class)aClass detailSelector:(SEL)selector;
- (void)attachToClass:(Class)aClass navigationSelector:(SEL)selector;
- (void)attachToClass:(Class)aClass accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector;

#pragma mark Object State

- (BOOL)isObjectActionable:(id<NSObject>)object;
- (BOOL)objectHasAccessoryView:(id<NSObject>)object;

+ (id)objectFromKeyClass:(Class)keyClass map:(NSMutableDictionary *)map;

@@ -213,6 +240,31 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @fn NIActions::attachToObject:navigationBlock:
*/

/**
* Attaches a tap action with an accessory view to the given object.
*
* A cell with an attached tap action will have its selectionStyle set to
* @c tableViewCellSelectionStyle when the cell is displayed.
*
* The action will be executed when the object's corresponding cell is tapped. The object argument
* of the block will be the object to which this action was attached. The target argument of the
* block will be this receiver's @c target.
*
* Return NO if the tap action is used to present a modal view controller. This provides a visual
* reminder to the user when the modal controller is dismissed as to which cell was tapped to invoke
* the modal controller.
*
* The tap action will be invoked first, followed by the navigation action if one is attached.
*
* @param object The object to attach the action to. This object must be contained within
* an NITableViewModel.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param action The tap action block.
* @returns The object that you attached this action to.
* @fn NIActions::attachToObject:accessoryView:tapBlock:
* @sa NIActions::attachToObject:accessoryView:tapSelector:
*/

/**
* Attaches a tap selector to the given object.
*
@@ -294,6 +346,38 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @sa NIActions::attachToObject:navigationBlock:
*/

/**
* Attaches a tap selector with an accessory view to the given object.
*
* The method signature for the selector is:
@code
- (BOOL)didTapObject:(id)object;
@endcode
*
* A cell with an attached tap action will have its selectionStyle set to
* @c tableViewCellSelectionStyle when the cell is displayed.
*
* The selector will be performed on the action object's target when a cell with a tap selector is
* tapped, unless that selector does not exist on the @c target in which case nothing happens.
*
* If the selector invocation returns YES then the cell will be deselected immediately after the
* invocation completes its execution. If NO is returned then the cell's selection will remain.
*
* Return NO if the tap action is used to present a modal view controller. This provides a visual
* reminder to the user when the modal controller is dismissed as to which cell was tapped to invoke
* the modal controller.
*
* The tap action will be invoked first, followed by the navigation action if one is attached.
*
* @param object The object to attach the selector to. This object must be contained within
* an NITableViewModel.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param selector The selector that will be invoked by this action.
* @returns The object that you attached this action to.
* @fn NIActions::attachToObject:accessoryView:tapSelector:
* @sa NIActions::attachToObject:accessoryView:tapBlock:
*/

/** @name Mapping Classes */

/**
@@ -329,6 +413,18 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @fn NIActions::attachToClass:navigationBlock:
*/

/**
* Attaches a tap block with an accessory view to a class.
*
* This method behaves similarly to attachToObject:tapBlock: except it attaches a tap action to
* all instances and subclassed instances of a given class.
*
* @param aClass The class to attach the action to.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param action The tap action block.
* @fn NIActions::attachToClass:accessoryView:tapBlock:
*/

/**
* Attaches a tap selector to a class.
*
@@ -362,6 +458,18 @@ NIActionBlock NIPushControllerAction(Class controllerClass);
* @fn NIActions::attachToClass:navigationSelector:
*/

/**
* Attaches a tap selector with an accessory view to a class.
*
* This method behaves similarly to attachToObject:tapBlock: except it attaches a tap action to
* all instances and subclassed instances of a given class.
*
* @param aClass The class to attach the action to.
* @param accessoryView The custom accessoryView to be added. If set, ignore cell accessoryType.
* @param selector The tap selector.
* @fn NIActions::attachToClass:accessoryView:tapSelector:
*/

/** @name Object State */

/**
87 changes: 80 additions & 7 deletions src/core/src/NIActions.m
Original file line number Diff line number Diff line change
@@ -25,7 +25,10 @@ @interface NIActions()

@property (nonatomic, NI_STRONG) NSMutableDictionary* objectMap;
@property (nonatomic, NI_STRONG) NSMutableSet* objectSet;
@property (nonatomic, NI_STRONG) NSMutableDictionary* classMap;
@property (nonatomic, NI_STRONG) NSMutableDictionary* objectClassMap;
@property (nonatomic, NI_STRONG) NSMutableDictionary* accessoryMap;
@property (nonatomic, NI_STRONG) NSMutableSet* accessorySet;
@property (nonatomic, NI_STRONG) NSMutableDictionary* accessoryClassMap;

@end

@@ -37,7 +40,10 @@ @implementation NIActions

@synthesize objectMap = _objectMap;
@synthesize objectSet = _objectSet;
@synthesize classMap = _classMap;
@synthesize objectClassMap = _objectClassMap;
@synthesize accessoryMap = _accessoryMap;
@synthesize accessorySet = _accessorySet;
@synthesize accessoryClassMap = _accessoryClassMap;


///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -46,7 +52,10 @@ - (id)initWithTarget:(id)target {
_target = target;
_objectMap = [[NSMutableDictionary alloc] init];
_objectSet = [[NSMutableSet alloc] init];
_classMap = [[NSMutableDictionary alloc] init];
_objectClassMap = [[NSMutableDictionary alloc] init];
_accessoryMap = [[NSMutableDictionary alloc] init];
_accessorySet = [[NSMutableSet alloc] init];
_accessoryClassMap = [[NSMutableDictionary alloc] init];
}
return self;
}
@@ -76,6 +85,10 @@ - (id)keyForObject:(id<NSObject>)object {
// actionForObjectOrClassOfObject: determines whether an action has been attached to an object
// or class of object and then returns the NIObjectActions or nil if no actions have been attached.
//
// accessoryViewForObjectOrClassOfObject: determines whether an accessoryView has been attached to
// an object or class of object and then returns the UIView or nil if no accessoryView has been
// attached.
//


///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,10 +109,10 @@ - (NIObjectActions *)actionForObject:(id<NSObject>)object {
// Retrieves an NIObjectActions object for the given class or creates one if it doesn't yet exist
// so that actions may be attached.
- (NIObjectActions *)actionForClass:(Class)class {
NIObjectActions* action = [self.classMap objectForKey:class];
NIObjectActions* action = [self.objectClassMap objectForKey:class];
if (nil == action) {
action = [[NIObjectActions alloc] init];
[self.classMap setObject:action forKey:(id<NSCopying>)class];
[self.objectClassMap setObject:action forKey:(id<NSCopying>)class];
}
return action;
}
@@ -111,12 +124,24 @@ - (NIObjectActions *)actionForObjectOrClassOfObject:(id<NSObject>)object {
id key = [self keyForObject:object];
NIObjectActions* action = [self.objectMap objectForKey:key];
if (nil == action) {
action = [self.class objectFromKeyClass:object.class map:self.classMap];
action = [self.class objectFromKeyClass:object.class map:self.objectClassMap];
}
return action;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
// Fetches any accessoryView for a given object.
- (UIView *)accessoryViewForObjectOrClassOfObject:(id<NSObject>)object {
id key = [self keyForObject:object];
UIView* accessoryView = [self.accessoryMap objectForKey:key];
if (nil == accessoryView) {
accessoryView = [self.class objectFromKeyClass:object.class map:self.accessoryClassMap];
}
return accessoryView;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Public Methods
@@ -146,6 +171,16 @@ - (id)attachToObject:(id<NSObject>)object navigationBlock:(NIActionBlock)action
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action {
[self.objectSet addObject:object];
[self actionForObject:object].tapAction = action;
[self.accessorySet addObject:object];
[self.accessoryMap setObject:accessoryView forKey:[self keyForObject:object]];
return object;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object tapSelector:(SEL)selector {
[self.objectSet addObject:object];
@@ -170,6 +205,16 @@ - (id)attachToObject:(id<NSObject>)object navigationSelector:(SEL)selector {
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)attachToObject:(id<NSObject>)object accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector {
[self.objectSet addObject:object];
[self actionForObject:object].tapSelector = selector;
[self.accessorySet addObject:object];
[self.accessoryMap setObject:accessoryView forKey:[self keyForObject:object]];
return object;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)attachToClass:(Class)aClass tapBlock:(NIActionBlock)action {
[self actionForClass:aClass].tapAction = action;
@@ -188,6 +233,13 @@ - (void)attachToClass:(Class)aClass navigationBlock:(NIActionBlock)action {
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)attachToClass:(Class)aClass accessoryView:(UIView *)accessoryView tapBlock:(NIActionBlock)action {
[self.accessoryClassMap setObject:accessoryView forKey:(id<NSCopying>)aClass];
[self actionForClass:aClass].tapAction = action;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)attachToClass:(Class)aClass tapSelector:(SEL)selector {
[self actionForClass:aClass].tapSelector = selector;
@@ -206,6 +258,13 @@ - (void)attachToClass:(Class)aClass navigationSelector:(SEL)selector {
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)attachToClass:(Class)aClass accessoryView:(UIView *)accessoryView tapSelector:(SEL)selector {
[self.accessoryClassMap setObject:accessoryView forKey:(id<NSCopying>)aClass];
[self actionForClass:aClass].tapSelector = selector;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)isObjectActionable:(id<NSObject>)object {
if (nil == object) {
@@ -214,12 +273,26 @@ - (BOOL)isObjectActionable:(id<NSObject>)object {

BOOL objectIsActionable = [self.objectSet containsObject:object];
if (!objectIsActionable) {
objectIsActionable = (nil != [self.class objectFromKeyClass:object.class map:self.classMap]);
objectIsActionable = (nil != [self.class objectFromKeyClass:object.class map:self.objectClassMap]);
}
return objectIsActionable;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)objectHasAccessoryView:(id<NSObject>)object {
if (nil == object) {
return NO;
}

BOOL objectHasAccessory = [self.accessorySet containsObject:object];
if (!objectHasAccessory) {
objectHasAccessory = (nil != [self.class objectFromKeyClass:object.class map:self.accessoryClassMap]);
}
return objectHasAccessory;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
+ (id)objectFromKeyClass:(Class)keyClass map:(NSMutableDictionary *)map {
id object = [map objectForKey:keyClass];
8 changes: 7 additions & 1 deletion src/models/src/NITableViewActions.m
Original file line number Diff line number Diff line change
@@ -172,9 +172,15 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce
NITableViewModel* model = (NITableViewModel *)tableView.dataSource;
id object = [model objectAtIndexPath:indexPath];
if ([self isObjectActionable:object]) {
cell.accessoryType = [self accessoryTypeForObject:object];
if ([self objectHasAccessoryView:object]) {
cell.accessoryView = [self accessoryViewForObjectOrClassOfObject:object];
} else {
cell.accessoryView = nil;
cell.accessoryType = [self accessoryTypeForObject:object];
}
cell.selectionStyle = [self selectionStyleForObject:object];
} else {
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}

0 comments on commit 94c3e69

Please sign in to comment.