snippetModerate
How can I condense several IBAction methods in a class with a delegate?
Viewed 0 times
canibactionwithcondenseseveralmethodsdelegatehowclass
Problem
I have the following class:
MyProtocolClass.h
MyProtocolClass.m
And this is a fairly simple example. The problem here is that I have a view with three buttons, and each button has it's own method, which simply calls a method on the delegate with an index to tell the delegate which button was pressed.
Surely there's a way to simplify this code and improve its readability. A more complex view with several more interactive UI elements would quickly make this file very large if we have to add another 4 lines to the file for each interactive UI element we add to the screen.
MyProtocolClass.h
#import
@protocol MyExampleProtocol
@required
- (void)someRequiredMethod:(NSInteger)someValue;
@end
@interface MyProtocolClass : UIView
// interface stuff
@endMyProtocolClass.m
#import "MyProtocolClass.h"
@interface MyProtocolClass()
@property (nonatomic,assign) id delegate;
@end
@implementation MyProtocolClass
// implementation stuff
- (IBAction)fooMethod:(id)sender {
[self.delegate someRequiredMethod:0];
}
- (IBAction)barMethod:(id)sender {
[self.delegate someRequiredMethod:1];
}
- (IBAction)fooBarMethod:(id)sender {
[self.delegate someRequiredMethod:2];
}
@endAnd this is a fairly simple example. The problem here is that I have a view with three buttons, and each button has it's own method, which simply calls a method on the delegate with an index to tell the delegate which button was pressed.
Surely there's a way to simplify this code and improve its readability. A more complex view with several more interactive UI elements would quickly make this file very large if we have to add another 4 lines to the file for each interactive UI element we add to the screen.
Solution
You're right. There is a simpler way.
First of all, instead of giving every interactive element its own method, let's give them all the same method.
If they're not all buttons, a different method name is in line, but for this example, I'll assume them all to be buttons.
Now then, whether you're creating these UI elements programmatically or via interface builder, the next important step is to give each element its own unique tag. In the Interface Builder, this is done under the "Attributes Inspector" (the icon that looks like a shield). The "tag" field is the second field under the "View" heading. It doesn't matter what tag you give the button. It only matters that the tags are unique.
Setting the tag programmatically is as simple as this:
Now, instead of a different method for each button (or other UI element), we can simply use a single button:
Now we've condensed your code. But we can do even better.
Let's create an
This should be placed in the
Now we just have to set our button tags to match these enum values. The good news is, if we're doing it programmatically, we can use the enum itself to set the values. For example...
And now we slightly modify our
And our delegate can implement the delegate method in some fashion like this:
First of all, instead of giving every interactive element its own method, let's give them all the same method.
- (IBAction)buttonPressed:(id)sender;If they're not all buttons, a different method name is in line, but for this example, I'll assume them all to be buttons.
Now then, whether you're creating these UI elements programmatically or via interface builder, the next important step is to give each element its own unique tag. In the Interface Builder, this is done under the "Attributes Inspector" (the icon that looks like a shield). The "tag" field is the second field under the "View" heading. It doesn't matter what tag you give the button. It only matters that the tags are unique.
Setting the tag programmatically is as simple as this:
myButton.tag = 100;Now, instead of a different method for each button (or other UI element), we can simply use a single button:
- (IBAction)buttonPressed:(id)sender {
[self.delegate someRequiredMethod:sender.tag];
}Now we've condensed your code. But we can do even better.
Let's create an
enum so that we're not just sending arbitrary numbers, but instead we send values that the delegate can make more sense of (and if using a switch, Xcode will help the delegate be sure he accounts for every case).typedef NS_ENUM(NSInteger, MyExampleButtonEnum) {
ButtonIndexUnknown = 0,
ButtonIndexTopLeft = 100,
ButtonIndexTopRight = 101,
ButtonIndexBottomLeft = 102,
ButtonIndexBottomRight = 103
};This should be placed in the
.h and before our @protocol. Then we can change our protocol to look like this instead:@protocol MyExampleProtocol
@required
- (void)someRequiredMethod:(MyExampleButtonEnum)button;
@endNow we just have to set our button tags to match these enum values. The good news is, if we're doing it programmatically, we can use the enum itself to set the values. For example...
UIButton *topLeftButton = [[UIButton alloc] initWithFrame:someFrame];
topLeftButton.tag = ButtonIndexTopLeft;
[topLeftButton addTarget:self action:@selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside]And now we slightly modify our
buttonPressed: method as such:- (IBAction)buttonPressed:(id)sender {
if (sender) {
[self.delegate someRequiredMethod:sender.tag];
} else {
[self.delegate someRequiredMethod:ButtonIndexUnknown];
}
}And our delegate can implement the delegate method in some fashion like this:
- (void)someRequiredMethod:(MyExampleButtonEnum)button {
switch(button) {
case ButtonIndexTopLeft:
// do stuff
break;
case ButtonIndexTopRight:
// do stuff
break;
case ButtonIndexBottomLeft:
// do stuff
break;
case ButtonIndexBottomRight:
// do stuff
break;
case ButtonIndexUnknown:
default:
// do stuff
break;
}
}Code Snippets
- (IBAction)buttonPressed:(id)sender;myButton.tag = 100;- (IBAction)buttonPressed:(id)sender {
[self.delegate someRequiredMethod:sender.tag];
}typedef NS_ENUM(NSInteger, MyExampleButtonEnum) {
ButtonIndexUnknown = 0,
ButtonIndexTopLeft = 100,
ButtonIndexTopRight = 101,
ButtonIndexBottomLeft = 102,
ButtonIndexBottomRight = 103
};@protocol MyExampleProtocol <NSObject>
@required
- (void)someRequiredMethod:(MyExampleButtonEnum)button;
@endContext
StackExchange Code Review Q#41761, answer score: 11
Revisions (0)
No revisions yet.