Reusing the UIViewController subclass I made for very similar but not identical situations: Recommended?
I'm still relatively new to iOS development and wondered if this is really a good thing.
For example, let's say I have two different contexts in which I want to represent identical / similar data in the same / similar ways, but there are some differences, perhaps some different buttons from one context to another, or different things that I need to do to prepare data. Should I just use multiple setting methods in one view controller and call any of them as needed, or have two separate view controllers?
I lean heavily towards the first, being correct because it seems much more efficient and saves a lot of identical code, but just in case I'd like to get it from experienced programmers.
source to share
You need to create three types of controller: SuperViewController
, FirstViewController
and SecondViewController
. FirstViewController
and SecondViewController
should be subclasses of yours SuperViewController
. Then you should consider the following:
Variables and properties
Declare all shared variables between your view controllers in SuperViewController
.
Declare any variables and properties of the visibility manager controller in the appropriate view controller.
Methods
As with properties, define any generic methods in SuperViewController
along with their implementation.
If you have methods that share some, but not all of their code between your view controllers, follow these steps:
1) In yours, SuperViewController
implement this method:
-(void)someSemiSharedMethod {
// put the common code here
}
2) In controllers of your kind:
-(void)someSemiSharedMethod {
// call the superclass' implementation of this method
// to ensure that common code is executed
[super someSemiSharedMethod];
// now add any child controller specific code to this method below
}
These are seams as the best approach to what you want to achieve. Let me know if you have any other questions or if this approach doesn't fully achieve what you want.
source to share
You can use the parent superclass method described by Andrew, but there is another option.
Subclassification is very powerful, but sometimes difficult to reason. If there is an error in one of the child controllers, it can be difficult to determine where the error really lies.
If the view controller settings are small, you can express this using arguments to the constructor, for example:
- (instancetype)initWithSaveButton(BOOL)includeSaveButton;
Or, if you need to customize some behavior, execute the block:
- (instancetype)initWithSaveAction:(void (^)(Person *))saveAction;
If the settings are minimal, I find this is a cleaner solution than subclassing.
EDIT : side of a note, but @leiyun asked a big question about BOOL checkboxes - what if we want to choose between button A and button B? Should we design an init method like this?
- (instancetype)initWithButtonA:(BOOL)includeA buttonB:(BOOL)includeB;
Ok this is a great example of why BOOL flags should be avoided. If we call this method like initWithButtonA:YES buttonB:YES
that, then we enter undefined behavior because we want to choose between these buttons.
So, for this, define the type of the parameters.
typedef enum {
MyViewControllerModeNoButtons,
MyViewControllerModeButtonA,
MyViewControllerModeButtonB
} MyViewControllerMode;
- (instancetype)initWithMode:(MyViewControllerMode)mode;
The guiding principle for such interfaces is that there should be no wrong way to call it. It also allows for better placement of more options if you need a third button or image or whatever!
source to share
For completeness, I want to also point out what I will consider as a third option after Andriy and joerick's answers, especially for the "different things I need to do to prepare the data": scenario: actually using the same view controller class for both screens, but by creating separate data source objects for each context that store, prepare, and provide the appropriate data.
These data source objects can be simple NSObject subclasses that conform to the protocol. For the usual ways of displaying data, there are already predefined protocols for data sources, such as UITableViewDataSource and UICollectionViewDataSource. If they don't suit your needs, you can of course define your own protocol. The data source can be stored by an instance of the view controller as a property, for example:
@property (strong, nonatomic) id<UITableViewDataSource> myDataSource;
You can "give" the appropriate data source to your view controller on initialization, for example.
-(instancetype)initWithDataSource: (id<UITableViewDataSource>) dataSource
source to share