Reputation:
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?
Upvotes: 16
Views: 9135
Reputation: 17844
I just want to clarify what @Felixyz said because it wasn't clear to me at first.
If you are subclassing UIControl
, even if you are going to have a custom event, you don't have to keep track of your own targets/actions. The functionality is already there, all you have to do is call the code below in your subclass to trigger the event:
[self sendActionsForControlEvents:UIControlEventValueChanged];
Then in the view or view controller that instantiates your custom UIControl
, just do
[customControl addTarget:self action:@selector(whatever) forControlEvents:UIControlEventValueChanged];
For custom event, just define your own enum (for example, UIControlEventValueChanged
is equal to 1 << 12
). Just make sure it is within the permitted range defined by UIControlEventApplicationReserved
Upvotes: 39
Reputation: 119214
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 = [[self 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)];
Upvotes: 15
Reputation: 19143
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.
Upvotes: 5