开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜