Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot find protocol declaration

I have two view controllers A and B, and they both have each other as their delegates.

When I did nothing except define the protocols at the beginning of the header files and #import the other's header file, I got two errors along the lines of -

cannot find protocol declaration for "BDelegate", which was showing in A.h (where I wrote ) cannot find protocol declaration for "ADelegate", which was showing in B.h (where I wrote )

Looking online, people had written earlier that the circular inclusion of header files could be leading to the problems. They recommended either using #include instead, or @class declaration like -

@class A 

instead of

#import A.h 

inside #import B.h

I have tried almost every combination of these imports, and @classes, and #include but still can't get rid of the warnings. Also, solutions online recommended moving the #import to the .m files but that didn't help either. Part of the reason is that the solutions online are kinda fuzzy - if you could break it down that would be great.

Any suggestions about what can be done to fix this?


-- BigViewController.h --

#import "BaseViewController.h" #include "BaseViewController.h"  @class BigViewController;  @protocol BigViewControllerDelegate -(void) BigViewController:(BigViewController *) bigView; @end  @interface BigViewController : UIViewController <BaseViewControllerDelegate> {          //delegate      id <BigViewControllerDelegate> delegate;  ivars...     }  @properties... @end  -------------------------------------------------- 

-- BaseViewController.h --

#<UIKit/UIKit.h>  #import "BigViewController.h" #include "BigViewController.h"  @class BigViewController;  @protocol BaseViewControllerDelegate - (void) setParametersWithItemChosen:(Item *) item; @end  @interface BaseViewController : UIViewController <...BigViewControllerDelegate...> {     ivars...     //delegate     id <BaseViewControllerDelegate> delegate; }  @properties... @end 
like image 229
Ak1 Avatar asked Jun 22 '11 23:06

Ak1


1 Answers

Let me reduce the sample even further, and label the lines:

VC1.h

#import "VC2.h"  // A  @class VC1;  @protocol VC1Delegate // B @end  @interface VC1 : UIViewController <VC2Delegate> // C @end 

VC2.h

#import "VC1.h"  // D  @class VC2;  @protocol VC2Delegate // E @end  @interface VC2 : UIViewController <VC1Delegate> // F @end 

Consider what happens when something #imports VC1.h: It reaches line A, then the import is processed. Line D does nothing because VC1.h was already imported. Then line E is processed. Then line F, and we get an error because we haven't gotten to line B yet so the protocol is not declared!

Consider then what happens when something #imports VC2.h: It reaches line D, then the import is processed. Line A does nothing because VC2.h was already imported. Then line B is processed. Then line C, and we get an error because we haven't gotten to line E yet so the protocol is not declared!

The first step is to reconsider whether both of these classes really need to be each other's delegates. If you can break the cycle, that would probably be the way to go. If not, you'll need to restructure your headers. The most straightforward way is probably to put the delegates into their own headers:

VC1Delegate.h

@class VC1;  @protocol VC1Delegate // B @end 

VC1.h

#import "VC1Delegate.h" #import "VC2Delegate.h"  @interface VC1 : UIViewController <VC2Delegate> // C @end 

VC2Delegate.h

@class VC2;  @protocol VC2Delegate // E @end 

VC2.h

#import "VC1Delegate.h" #import "VC2Delegate.h"  @interface VC2 : UIViewController <VC1Delegate> // F @end 

If you trace through the imports now, you'll see that the appropriate protocols will now always be declared before the @interface lines try to use them.

like image 94
Anomie Avatar answered Oct 02 '22 17:10

Anomie