Objective-C Pointer to class that implements a protocol
I have three classes which implement the same protocol, and have the same parent class which doesn't implement the protocol. Normally I would have the protocol as pure virtual function开发者_开发百科s in the parent class but I couldn't find an Objective-C way to do that.
I want to utilize polymorphism on these subclasses by declaring pure virtual functions in the superclass then have the children implement those functions. However the only Objective-C way I've found to do this is to have each child explicitly decide to implement a protocol, when I do it this way the superclass doesn't know the children will implement that protocol so there are compile time warnings all over the place.
Some pseudo-code if that didn't make sense:
@interface superclass: NSObject
{}
@interface child1: superclass<MyProtocol>
{}
@interface child2: superclass<MyProtocol>
{}
The consumer of these classes:
@class child1
@class child2
@class superclass
@interface SomeViewController: UIViewController
{
child1 *oneView;
child2 *otherView;
superclass *currentView;
}
-(void) someMethod
{
[currentView protocolFunction];
}
The only nice way I've found to do pure virtual functions in Objective-C is a hack by putting [self doesNotRecognizeSelector:_cmd];
in the parent class, but it isn't ideal since it will cause runtime errors rather than compile time.
Objective-C developers commonly use dynamic checking rather than compile-time checking in these situations because the language and the frameworks support it so well. So for example, you could write your method like this:
- (void)someMethod
{
// See if the object in currentView conforms to MyProtocol
//
if ([currentView conformsToProtocol:@protocol(MyProtocol)])
{
// Cast currentView to the protocol, since we checked to make
// sure it conforms to it. This keeps the compiler happy.
//
[(SuperClass<MyProtocol> *) currentView protocolMethod];
}
}
I was able to get the compiler to warn me correctly by making the superclass *currentView
property look like this:
@property (nonatomic, retain) superclass<MyProtocol> *currentView;
Alternatively you can use the following
if ([unknownObject conformsToProtocol:@protocol(MyProtocol)])
[unknownObject performSelector:@selector(methodInProtocol)];
instead of the following if you just want to suppress the warning.
if ([unknownObject conformsToProtocol:@protocol(MyProtocol)])
[unknownObject methodInProtocol]; // will cause warning
performSelector: will only work if the number of arguments is zero or one. More flexible invocations can be achieved with NSInvocation.
Personally, I would implement the protocol on the super class, but implement the methods like this:
- (id) myProtocolMethod {
NSAssert(NO, [NSString stringWithFormat:@"-[%@ %@] must be overridden", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]);
return nil;
}
That way if you ever forget to override a method in a concrete subclass, it should be immediately obvious.
精彩评论