Xcode warns about missing protocol definition, even though @protocol is used

  • Since I had a import-cycle recently, I'm moving all #import statements (concerning my own files) from the header into the corresponding .m-file. I also added @class and @protocol forward-declarations to soothe the compiler. However, I still get he following warning:

        Cannot find the protocol definition for 'MyCustomDelegate'.

    As I said, there is an @protocol MyCustomDelegate before I use it in the @interface-Block. Interestingly this warning only occurs if the corresponding delegate is declared in another file (whose header is imported in the .m-file).

    I read that one solution is to declare the delegate in a separate header file and import that file directly in the header of the class that implements the delegate. Is this really the way to go? Are there any other solutions? I think those delegates already bloated our code enough, now I should go on and even declare an own file for it?

    Small sample code to better illustrate the problem:

    NewFooController.h:
        #import <UIKit/UIKit.h>
        @protocol NewFooControllerDelegate;
        @interface NewFooController : UITableViewController
            @property (nonatomic, weak) id<NewFooControllerDelegate> delegate;
        @end

        @protocol NewFooControllerDelegate
        @end

    HomeTableViewController.h:
        #import <UIKit/UIKit.h>
        // warning points to line below
        @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
        @end

    HomeTableViewController.m:
        #import "HomeTableViewController.h"
        #import "NewFooController.h"
        @implementation HomeTableViewController
        @end
  • On Apr 14, 2012, at 5:55 AM, Florian Pilz wrote:

    > NewFooController.h:
    > #import <UIKit/UIKit.h>
    > @protocol NewFooControllerDelegate;
    > @interface NewFooController : UITableViewController
    > @property (nonatomic, weak) id<NewFooControllerDelegate> delegate;
    > @end
    >
    > @protocol NewFooControllerDelegate
    > @end
    >
    > HomeTableViewController.h:
    > #import <UIKit/UIKit.h>
    > // warning points to line below
    > @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
    > @end

    You never imported NewFooController.h here, so when the compiler is compiling something that imported HomeTableViewController.h, it can't find the @protocol definition.

    --Kyle Sluder
  • The import is done in the ".m"-file of HomeTableViewController. But I just found a fault in my sample code anyways: the ".h"-file of HomeTableViewController should have an "@protocol NewFooController" declaration.

    Corrected sample code for HomeTableViewController.h:

        #import <UIKit/UIKit.h>
        @protocol NewFooControllerDelegate;
        // warning points to line below
        @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
        @end

    On Saturday, 14 April 2012 at 19:00, Kyle Sluder wrote:

    > On Apr 14, 2012, at 5:55 AM, Florian Pilz wrote:
    >
    >> NewFooController.h:
    >> #import <UIKit/UIKit.h>
    >> @protocol NewFooControllerDelegate;
    >> @interface NewFooController : UITableViewController
    >> @property (nonatomic, weak) id<NewFooControllerDelegate> delegate;
    >> @end
    >>
    >> @protocol NewFooControllerDelegate
    >> @end
    >>
    >> HomeTableViewController.h:
    >> #import <UIKit/UIKit.h>
    >> // warning points to line below
    >> @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
    >> @end
    >>
    >
    >
    >
    > You never imported NewFooController.h here, so when the compiler is compiling something that imported HomeTableViewController.h, it can't find the @protocol definition.
    >
    > --Kyle Sluder
  • On 16.04.2012, at 23:03, Florian Pilz wrote:
    > The import is done in the ".m"-file of HomeTableViewController. But I just found a fault in my sample code anyways: the ".h"-file of HomeTableViewController should have an "@protocol NewFooController" declaration.
    >
    > Corrected sample code for HomeTableViewController.h:
    >
    > #import <UIKit/UIKit.h>
    > @protocol NewFooControllerDelegate;
    > // warning points to line below
    > @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
    > @end

    That won't work. When you declare a class as conforming to a protocol, the compiler has to know what methods that protocol contains, so it can make sure to complain if one of the required methods is missing.

    @protocol Foo only works if you want to declare a variable of type id<Foo> (but not actually send messages to it). It simply tells the compiler "this protocol exists", but not what methods it actually consists of.

    It's the same as with plain C struct Foo; and struct Foo { int x; int y; }; Only the latter can actually be used (because now the compiler knows that there is a struct named 'Foo'), but you can declare pointers to the former, because for a pointer it only has to know the size of an address, not the size of the struct at that address.

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.masters-of-the-void.com
  • A thanks, that explains a lot. I'm just a bit confused why the compiler needs to know the declared methods in the header file - I can't imagine a case where a protocol method is 'used' in the header. In the implementation file it's clear to me that the protocol must be known, however it's imported there so that shouldn't be an issue.

    -- Florian Pilz

    On Monday, 16 April 2012 at 23:28, Uli Kusterer wrote:

    > On 16.04.2012, at 23:03, Florian Pilz wrote:
    >> The import is done in the ".m"-file of HomeTableViewController. But I just found a fault in my sample code anyways: the ".h"-file of HomeTableViewController should have an "@protocol NewFooController" declaration.
    >>
    >> Corrected sample code for HomeTableViewController.h:
    >>
    >> #import <UIKit/UIKit.h>
    >> @protocol NewFooControllerDelegate;
    >> // warning points to line below
    >> @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
    >> @end
    >>
    >
    >
    >
    > That won't work. When you declare a class as conforming to a protocol, the compiler has to know what methods that protocol contains, so it can make sure to complain if one of the required methods is missing.
    >
    > @protocol Foo only works if you want to declare a variable of type id<Foo> (but not actually send messages to it). It simply tells the compiler "this protocol exists", but not what methods it actually consists of.
    >
    > It's the same as with plain C struct Foo; and struct Foo { int x; int y; }; Only the latter can actually be used (because now the compiler knows that there is a struct named 'Foo'), but you can declare pointers to the former, because for a pointer it only has to know the size of an address, not the size of the struct at that address.
    >
    > Cheers,
    > -- Uli Kusterer
    > "The Witnesses of TeachText are everywhere..."
    > http://www.masters-of-the-void.com
    >
    >
  • Hi again. I just stumbled about this problem for another time and rethought Ulis explanation. The point of my writing is: Ulis explanation is wrong. The program compiles (with a warning) and runs perfectly fine. So basically Xcode tells me, that it must know the implementation details, which are not given in the header file (but may be added in the implementation file -- therefore a warning rather an error).

    Is there a flag to disable such a warning?

    Best wishes
    Florian

    Am Montag, 16 April 2012 um 23:28 schrieb Uli Kusterer:

    > On 16.04.2012, at 23:03, Florian Pilz wrote:
    >> The import is done in the ".m"-file of HomeTableViewController. But I just found a fault in my sample code anyways: the ".h"-file of HomeTableViewController should have an "@protocol NewFooController" declaration.
    >>
    >> Corrected sample code for HomeTableViewController.h:
    >>
    >> #import <UIKit/UIKit.h>
    >> @protocol NewFooControllerDelegate;
    >> // warning points to line below
    >> @interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
    >> @end
    >>
    >
    >
    >
    > That won't work. When you declare a class as conforming to a protocol, the compiler has to know what methods that protocol contains, so it can make sure to complain if one of the required methods is missing.
    >
    > @protocol Foo only works if you want to declare a variable of type id<Foo> (but not actually send messages to it). It simply tells the compiler "this protocol exists", but not what methods it actually consists of.
    >
    > It's the same as with plain C struct Foo; and struct Foo { int x; int y; }; Only the latter can actually be used (because now the compiler knows that there is a struct named 'Foo'), but you can declare pointers to the former, because for a pointer it only has to know the size of an address, not the size of the struct at that address.
    >
    > Cheers,
    > -- Uli Kusterer
    > "The Witnesses of TeachText are everywhere..."
    > http://www.masters-of-the-void.com
    >
    >
  • On May 3, 2012, at 2:54 PM, Florian Pilz wrote:

    > Hi again. I just stumbled about this problem for another time and rethought Ulis explanation. The point of my writing is: Ulis explanation is wrong. The program compiles (with a warning) and runs perfectly fine. So basically Xcode tells me, that it must know the implementation details, which are not given in the header file (but may be added in the implementation file -- therefore a warning rather an error).

    Please post your code in its entirety.

    I just tried this, and it gives me a warning:

    // t.m
    #import <Foundation/Foundation.h>

    @protocol FooProto;

    @interface SomeClass : NSObject <FooProto>
    @end

    @implementation SomeClass
    @end

    int main(int argc, char **argv)
    {
        [SomeClass new];
        return 0;
    }

    @protocol FooProto
    @end
    // END t.m

    % clang -o t t.m -framework Foundation
    t.m:5:34: warning: cannot find protocol definition for 'FooProto'
    1 warning generated.

    --Kyle Sluder
  • > I just tried this, and it gives me a warning:

    That is what he's complaining about... the warning.

    To the OP: there is no way a compiler can tell if a class conforms
    to a protocol when the only thing it knows is the name of the
    protocol.  Thus the warning.  Maybe it will compile and run...
    maybe not.

    Marc
  • On May 3, 2012, at 3:08 PM, Marco S Hyman wrote:

    >> I just tried this, and it gives me a warning:
    >
    > That is what he's complaining about... the warning.

    Except he just said he got it to compile without a warning, which means that whatever he's got going on is more complicated than the situation as Uli and I have understood it.

    >
    > To the OP: there is no way a compiler can tell if a class conforms
    > to a protocol when the only thing it knows is the name of the
    > protocol.  Thus the warning.  Maybe it will compile and run...
    > maybe not.

    Except the compiler produces the warning on the @interface, which provides no information about whether the class actually implements the required protocol methods. You don't need to redeclare methods from protocols you adopt. The logical place to emit this warning is on the @implementation, so the compiler can alert you that it can't verify you've _implemented_ all the methods you claim to.

    But even that's not good enough, because it would make it impossible to implement a proxy class that claims to conform to a protocol but actually forwards the messages to the object it's proxying via -forwardingTargetForSelector:, without getting warnings that the class hasn't implemented the protocol methods.

    --Kyle Sluder
  • On May 3, 2012, at 15:13 , Kyle Sluder wrote:

    > Except the compiler produces the warning on the @interface, which provides no information about whether the class actually implements the required protocol methods. You don't need to redeclare methods from protocols you adopt. The logical place to emit this warning is on the @implementation, so the compiler can alert you that it can't verify you've _implemented_ all the methods you claim to.

    As an aside, the second kind of information that the compiler needs is the inheritance chain for the protocol.

    The idea that the actual protocol declaration (as opposed to the forward reference) belongs with the implementation ignores the fact that the public @interface is all that clients of the class have to go on, and clients of the class typically need to know what methods form part of the protocol (and need to know the inheritance chain).

    If syntax permitted that the class @interface declared conformance only, clients would still need to include the actual protocol declaration from somewhere.

    In the special case of a delegate protocol, most clients of the class won't need to know even that the class implements the protocol, but in general the class @interface requires a complete protocol declaration for the benefit of clients.

    Incidentally, I only just discovered that you can declare conformance on a class extension:

    @interface MyClass () <SomeProtocol>

    while means there is a technique of privatizing the protocol conformance within the .m file, when conformance is an implementation detail of the class.
  • On May 3, 2012, at 3:33 PM, Quincey Morris wrote:

    > On May 3, 2012, at 15:13 , Kyle Sluder wrote:
    >
    >> Except the compiler produces the warning on the @interface, which provides no information about whether the class actually implements the required protocol methods. You don't need to redeclare methods from protocols you adopt. The logical place to emit this warning is on the @implementation, so the compiler can alert you that it can't verify you've _implemented_ all the methods you claim to.
    >
    > As an aside, the second kind of information that the compiler needs is the inheritance chain for the protocol.
    >
    > The idea that the actual protocol declaration (as opposed to the forward reference) belongs with the implementation ignores the fact that the public @interface is all that clients of the class have to go on, and clients of the class typically need to know what methods form part of the protocol (and need to know the inheritance chain).

    This is true; I hadn't thought about that. Especially since current advice is to make all your protocols conform to <NSObject>.

    --Kyle Sluder
  • On May 3, 2012, at 2:54 PM, Florian Pilz wrote:

    > Hi again. I just stumbled about this problem for another time and rethought Ulis explanation. The point of my writing is: Ulis explanation is wrong. The program compiles (with a warning) and runs perfectly fine.

    Well, Uli was wrong in implying that the compiler *has* to know the definition of the protocol. It can generate code without it. But he’s correct that the compiler wants to know the definition so it can do proper consistency checking.

    > So basically Xcode tells me, that it must know the implementation details, which are not given in the header file (but may be added in the implementation file -- therefore a warning rather an error).
    > Is there a flag to disable such a warning?

    Probably, but that’s the wrong approach. Warnings are there for a reason. If you disable the warning, then if you add a new method to the protocol later but don’t update a class that implements the protocol, you may not find out until your program throws an exception at runtime.

    You should instead add an #import to your header so that the actual protocol definition gets parsed before the class that implements it.

    (Also, this thread belongs on xcode-users or objc-language, not cocoa-dev.)

    —Jens
previous month april 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
Go to today