views:

690

answers:

2

I'm going to write my own custom control that is very different from UIButton. It's so much different that I decided to write it from scratch. So all I subclass is UIControl.

When my control is touched up inside, then I want to fire a message in means of target-action. The user of that class may instantiate it and then add some targets and actions for this event.

i.e. imagine I would call internally a method -fireTargetsForTouchUpEvent. How could I maintain this target-action-mechanism in my class? Do I have to add all targets and actions to my own array and then just call selectors (the actions) on the target objects in a for-loop? Or is there a more intelligent way to do it?

I imagine to provide some methods for adding targets and actions for some events like that touch up event (I raise that manually by calling a internal method when that happens). Any idea?

+4  A: 

You have the right idea. Here is how I would do it:

@interface TargetActionPair : NSObject
{
    id target;
    SEL action;
}
@property (assign) id target;
@property (assign) SEL action;
+ (TargetActionPair *)pairWithTarget:(id)aTarget andAction:(SEL)selector;
- (void)fire;
@end

@implementation TargetActionPair
@synthesize target;
@synthesize action;

+ (TargetActionPair *)pairWithTarget:(id)aTarget andAction:(SEL)anAction
{
    TargetActionPair * newSelf = [[TargetActionPair alloc] init];
    [newSelf setTarget:aTarget];
    [newSelf setAction:anAction];
    return [newSelf autorelease];
}

- (void)fire
{
    [target performSelector:action];
}

@end

With that class in place, storing your target/action pairs is pretty straightforward:

MyCustomControl.h:

#import "TargetActionPair.h"

@interface MyCustomControl : UIControl
{
    NSMutableArray * touchUpEventHandlers;
}

- (id)init;
- (void)dealloc;

- (void)addHandlerForTouchUp:(TargetActionPair *)handler;

@end

MyCustomControl.m:

#import "TargetActionPair.h"

@implementation MyCustomControl

- (id)init
{
    if ((self = [super init]) == nil) { return nil; }
    touchUpEventHandlers = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}

- (void)dealloc
{
    [touchUpEventHandlers release];
}

- (void)addHandlerForTouchUp:(TargetActionPair *)handler
{
    [touchUpEventHandlers addObject:handler];
}

- (void) fireTargetsForTouchUpEvent
{
    [touchUpEventHandlers makeObjectsPerformSelector:@selector(fire)];
}

@end

After that, setting up the control would be done as follows:

[instanceOfMyControl addHandlerForTouchUp:
         [TargetActionPair pairWithTarget:someController
                                andAction:@selector(touchUpEvent)];
e.James
wow, the biggest answer I've ever got here ;) thanks! For my case, I figured out UIControl seems to offer me already what I need. But when there are special custom events that need to be processed, your technique is excellent!
HelloMoon
Actually, for custom events you might want to use the UIControlEventApplicationReserved bits (16 available) and call -(void)sendActionsForControlEvents:(UIControlEvents)controlEvents;
Felixyz
+4  A: 

Since you're planning to subclass UIControl, you can just use

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

Using this, any class can register itself as a target for any events it wants to on your custom controller.

Felixyz