In an app, you might have the same action available in several UIViewController
or UIView
that is triggered via a user tapping on a button. For e.g. there might be multiple places in your app with a “Send Feedback” button or a reveal menu button. You might have code like this:
@implementation SomeViewController1
- (void)setUp {
[btn addTarget:self action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
- (void)menuTapped {
//Many
//lines
//of
//code to set up and display menu
}
@end
@implementation SomeViewController2
- (void)setUp {
[btn addTarget:self action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
- (void)menuTapped {
//Many
//lines
//of
//code to set up and display menu
}
@end
After repeating this in a few classes, you decided that duplicate code is bad, so you refactor it into:
@implementation SomeViewController1
- (void)setUp {
[btn addTarget:self action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
- (void)menuTapped {
[[UIApplication sharedApplication] menuTapped];
}
@end
@implementation SomeViewController2
- (void)setUp {
[btn addTarget:self action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
- (void)menuTapped {
[[UIApplication sharedApplication] menuTapped];
}
@end
@interface AppDelegate : NSObject
@implementation AppDelegate
- (void)menuTapped {
//Many
//lines
//of
//code to set up and display menu
}
@end
You move the common logic of setting up and display the menu into the AppDelegate
class and cut down on duplicate logic.
However, touch events are propagated upwards the responder chain if the target is nil
and the responder chain ends with the UIApplication
delegate1. So, if we pass nil
instead of self as the target when setting up the action on UIButton
, the event will ultimately be propagated to our UIApplication
delegate.
@implementation SomeViewController1
- (void)setUp {
[btn addTarget:nil action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
@end
@implementation SomeViewController2
- (void)setUp {
[btn addTarget:nil action:@selector(menuTapped) forControlEvents:UIControlEventTouchUpInside];
}
@end
@interface AppDelegate : NSObject
@end
@implementation AppDelegate
- (void)menuTapped {
//Many
//lines
//of
//code to set up and display menu
}
@end
We end up with shorter and less code.
Check out the developer docs for more details on how events are delivered
[1] The responder chain ends with the UIApplication
delegate only when the delegate inherits from UIResponder
. Recent versions of Xcode creates projects with the delegate inheriting from UIResponder
. If you have an existing project that was created using an old version of Xcode, you will need to change it yourself.↩
Your feedback is valuable: Do you want more nuggets like this? Yes or No
.
.