Reputation: 450
I'm developing an iOS application where I have a screen which displays some filters for a related search. Now I've made all of these filters as custom UIViews because they all have fairly different UI and they have to be reused on different screens. Inspite of their differences they all present a common interface to the View Controller managing them, so the view controller isn't concerned with what and how a filterView does something. It's only concerned with passing some data to them and retrieving their state through a property common to all of them. They all have their different classes which are subclasses of FilterView a subclass of UIView. This FilterView class presents an interface which all of these subclasses adopt.
This methodology works fine, but the problem is that all of the methods and properties a filterView should present are declared in the base class FilterView and if some particular filter doesn't implement a behavior it defaults to the behavior provided by its superclass FilterView. I don't want this. I want that every FilterView subclass should be required to provide an implementation on the FilterView API or otherwise provide their own defaults not the defaults of a superclass.
If I use a protocol to implement this behavior I loose the ability for all these classes to compulsorily be UIViews which is also a requirement.
Can you suggest what design pattern should I use to better manage all the different FilterView subclasses.
Upvotes: 0
Views: 415
Reputation: 450
This can be expressed clearly now in swift 4 by defining the common interface in a protocol named Filter
and then defining FilterView as:
typealias FilterView = UIView & Filter
Upvotes: 0
Reputation: 931
Define a protocol with non-optional methods -- "By default, all methods declared in a protocol are required methods. This means that any class that conforms to the protocol must implement those methods." Define a class that declares it implements the protocol. Now when a subclass of your parent class is written, the compiler will flag it as an error if the mandatory method(s) aren't implemented
and in super class you can write
//In super class
- (id)someMethod:(aObject*)param
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Your app will crash if subclass will not implement this method and you don't need to call
[super someMethod: param];
Upvotes: 0
Reputation: 8006
Well, if you think that all your filter objects need to provide a UIView
rather then explicitly being one, you can add this requirement to protocol. For example :
@protocol FilterObject
- (UIView *)viewForFilter;
@end
// Swift
protocol FilterObject {
func viewForFilter() -> UIView
}
And then in classes which actually are UIView
s just implement it like this :
- (UIView *)viewForFilter {
return self;
}
// Swift
func viewForFilter() -> UIView {
return self
}
For completeness sake, you can also kind of "force" the requirement to implement methods in subclassess by throwing an exception when their base implementation is called :
- (void) methodWithoutBaseImplementation {
// this goes in the base class
[NSException raise:NSInternalInconsistencyException format:@"This method needs to be implemented by subclasses! - %@", NSStringFromSelector(_cmd)];
}
// Swift
func methodWithoutBaseImplementation() {
NSException.raise(NSInternalInconsistencyException, format:"This method needs to be implemented by subclasses! - \(__FUNCTION__)")
}
This pattern to make Objective-C/Swift classess "abstract" can be foound in some of external libraries. Note that this is harder to achieve in Swift, as there is no dynamic dispatch in it - this means that if you cast your subclass to base class and call a method, the base implementation will be called. I'd advise against it though, as the protocol approach is safer, because it doesn't create a path where you crash your app. I've added this example just to illustrate the possibility and for completeness.
Upvotes: 2