Reputation: 42139
I have built a UIViewController
that implements various UI features. It is intended for a user to subclass so that they can update it with a few methods such as setContents:
and getContents
.
Within my UIViewController
I am calling a method when they tap a button that I want the user to implement in their subclass, showPicker
.
I would like the user to be able to be able to control what they do in this method, so I figured that they should just implement it within their subclass:
- (void)showPicker {
// Do what you want
}
In order to do this, I had to add a blank method of the same name in my original UIViewController
, then add it in the header file as well.
What I want to do is exactly like how you can subclass UIViewController
and then implement viewWillAppear:
and do what you want in that method.
Is this the correct pattern to follow if I want to allow the user to control what happens when a button inside of my class is tapped? Am I doing this all wrong? Should I be using delegates?
Upvotes: 0
Views: 438
Reputation: 17958
Creating a class designed to be subclassed will work and it isn't wrong (most frameworks depend on such classes). Whether or not this is actually the best option for you depends on how you expect the class to be used.
Subclassing makes sense if:
On the other hand a delegate may be a better choice if:
Blocks might also be a good fit for accepting small units of custom behavior without requiring additional classes.
Upvotes: 1
Reputation: 2075
If you want to emulate what UIViewController
does with viewWillAppear:
, you will need to add a do-nothing implementation of showPicker
in your base class. UIViewController.h
indicates that viewWillAppear:
has a default implementation that does nothing.
Delegates would complicate both your base class and the subclasses, without really simplifying much in return. They are really closer to a notification than an abstract method.
Other options here are to do something along the lines of:
if ([self canPerformSelector:@selector(showPicker)]) {
...
}
It doesn't give as much compile-time safety for my liking, but it is an alternative and keeps most of the responsibility in the base class. But I find that it isn't as discoverable as an empty method implementation in your base class.
If you don't want empty implementations for abstract methods in your base class, protocols may be a better fit, balancing discoverability and compile-time safety.
@protocol PickerProtocol <NSObject>
- (void)showPicker;
@end
@interface SomeBaseClass : UIViewController
...
@end
@implementation SomeBaseClass
- (void)someBaseClassMethod {
if ([self conformsToProtocol:@protocol(Picker)]) {
[(id<PickerProtocol>)self showPicker];
}
}
@end
Your subclasses opt-in by declaring that they have implemented the protocol, allowing the compiler to warn if you didn't implement all @required
methods.
@interface MySubClass <PickerProtocol>
...
@end
@implementation MySubClass
- (void)showPicker {
...
}
@end
This allows the compiler to show warnings and code completion. While it isn't as simple as empty base class methods, it does allow subclasses to explicitly declare that they offer some behavior.
If it's only a method here or there, I would use the empty method approach. If you have groups of methods that should be implemented together, I would use protocols.
Upvotes: 1