Protocol inheritance in Objective C

21,245

Solution 1

There is no official language definition for Objective-C, but according to Apple:

When a class adopts a protocol, it must implement the required methods the protocol declares, as mentioned earlier. In addition, it must conform to any protocols the adopted protocol incorporates. If an incorporated protocol incorporates still other protocols, the class must also conform to them. A class can conform to an incorporated protocol using either of these techniques:

  • Implementing the methods the protocol declares
  • Inheriting from a class that adopts the protocol and implements the methods

However, reports are that GCC doesn't recognize that the property is in an incorporated protocol and is implemented in a superclass. You could change your compiler to Clang, which is reported to handle this in the specified manner, or you could just use @dynamic to tell the compiler that an implementation of the property will be provided at run time (in this case, by inheritance from the superclass).

Solution 2

[XCode 3.2]

The compiler bug is in implementation of protocol inheritance. In the example when compiling POC there are two paths to ProductionProtocol:

  1. POC -> Production -> BaseProduction -> ProductionProtocol
  2. POC -> POCProtocol -> ProductionProtocol

This confuses GCC 4.2, it doesn't confuse Clang (LLVM 1.6, XCode 3.2).

If you change POCProtocol to:

@protocol POCProtocol//<ProductionProtocol>

the error will go away.

You could just comment out the protocol-to-protocol inheritance and leave a TODO to remove when the compiler is fixed.

Looks like a classic compiler writer bug to me, or maybe someone confused with .NET semantics (where you can re-implement interfaces (protocols in Obj-C) along the inheritance chain).

@danyowdee suggests you file a bug report, though as it is not in Clang (I didn't fire up my mothballed XCode 4 to test its compilers) I suspect this is unlikely to be a high priority to get fixed...

Share:
21,245
Matt McMinn
Author by

Matt McMinn

Lots of programming experience. As I'm sure you have too.

Updated on July 14, 2022

Comments

  • Matt McMinn
    Matt McMinn almost 2 years

    I've got a project which has in it a protocol, a class implementing that protocol, and a subclass of the implementation class. This is our production application.

    @protocol ProductionProtocol<NSObject>
    @property (nonatomic, retain) NSString *role;
    @end
    
    @interface BaseProduction : NSObject<ProductionProtocol>
    NSString *role;
    @end
    
    @implementation BaseProduction
    @synthesize role;
    @end
    
    @interface Production : BaseProduction
    @end
    
    @implementation Production
    @end
    

    I've also got a proof of concept (POC) application, which is implemented as a separate project that includes the production application. In the POC application, I have a protocol that extends the production protocol, and a class that extends the production class.

    @protocol POCProtocol<ProductionProtocol>
    -(void)cancel;
    @end
    
    @interface POC : Production<POCProtocol>
    @end
    
    @implementation POC
    -(void)cancel{...}
    @end
    

    Notice that in the ProductionProtocol, I've got a role NSString which is declared, and implemented in the BaseProduction interface/class. in the POC, I've got a method 'cancel' which is declared in the protocol, but not in the interface/class.

    So here's my question: with my class structure set up like this, I get this warning:

    Property 'role' requires method '-role' to be defined - use @synthesize, @dynamic or provide a method implementation
    

    I don't understand why I'm getting this warning. Since the synthesized properties are in the base class, they should be available to the POC class - and a quick test seems to confirm that they are. So what am I doing wrong here?

  • Steven Fisher
    Steven Fisher over 13 years
    FWIW, when I ran into this problem I was using clang. However, I can't remember if it was the Xcode 4 clang or not.
  • Anomie
    Anomie over 13 years
    @StevenFisher: I haven't tested gcc versus clang myself, but I've heard that clang fixes it. Maybe that's wrong. I know @dynamic works, at any rate.
  • Matt McMinn
    Matt McMinn over 13 years
    This is actually the method that I started with, and it worked fine for us for a while, but I wanted to see if I could make it work "correctly".
  • Matt McMinn
    Matt McMinn over 13 years
    I went with the @dynamic route - we're pushing for a release, and I don't want to rock the boat too much right now. Thanks!