views:

372

answers:

2

I'm looking for the correct way to write my own interface objects.

Say, I want an image that can be double-tapped.

@interface DoubleTapButtonView : UIView {
 UILabel *text;
 UIImage *button;
 UIImage *button_selected;
 BOOL selected;
}
// detect tapCount == 2
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

This works fine - the button receives the events and can detect double taps.

My question is how to cleanly handle actions. The two approaches I've tried are adding references to the parent object and delegation.

Passing a reference to the parent object is quite straightforward...

@interface DoubleTapButtonView : UIView {
 UILabel *text;
 UIImage *button;
 UIImage *button_selected;
 BOOL selected;
 MainViewController *parentView; // added
}

@property (nonatomic,retain) MainViewController *parentView; // added

// parentView would be assigned during init...
- (id)initWithFrame:(CGRect)frame 
     ViewController:(MainViewController *)aController;

- (id)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

But, this would prevent my DoubleTapButtonView class from being easily added to other views and view controllers.

Delegation adds some extra abstraction to the code, but it allows me to use the DoubleTapButtonView in any class that fits the delegate interface.

@interface DoubleTapButtonView : UIView {
 UILabel *text;
 UIImage *button;
 UIImage *button_selected;
 BOOL selected;
  id <DoubleTapViewDelegate> delegate;
}

@property (nonatomic,assign) id <DoubleTapViewDelegate> delegate;

@protocol DoubleTapViewDelegate <NSObject>

@required
- (void)doubleTapReceived:(DoubleTapView *)target;

This seems like the proper way to design the objects. The button only knows if it was doubletapped, and then tells the delegate who decides how to handle this information.

I'm wondering if there are any other ways of thinking about this problem? I noticed that UIButton uses the UIController and addTarget: to manage sending events. Is it desireable to leverage this system when writing my own interface objects?

Update: Another technique is using NSNotificationCenter to create observers for various events, and then create the event in the button.

// listen for the event in the parent object (viewController, etc)
[[NSNotificationCenter defaultCenter] 
  addObserver:self selector:@selector(DoubleTapped:) 
  name:@"DoubleTapNotification" object:nil];

// in DoubleTapButton, fire off a notification...
[[NSNotificationCenter defaultCenter] 
  postNotificationName:@"DoubleTapNotification" object:self];

What are the disadvantages to this approach? Less compile-time checking, and potential spaghetti code with events flying around outside of the object structure? (and even namespace collision if two developers use the same event name?)

+2  A: 

The delegate is definitely the way to go here.

August
+1  A: 

Or subclass UIControl and use -sendActionsForControlEvents:. Main advantage of that is multiple targets for particular actions... in this case, of course, you've only got the double-tap, but I think it's the best way to go in general.

Noah Witherspoon
Problem with UIControl is that there are a limited number of UIControlEvents to call - TouchUpInside etc. I don't see how to define a new event, such as "DoubleTap".
Jason Moore