web-dev-qa-db-fra.com

Impossible de trouver la déclaration de protocole

J'en ai deux view controllers A et B, et ils se sont tous les deux délégués.

Quand je n'ai rien fait sauf définir les protocoles au début des fichiers d'en-tête et #import le fichier d'en-tête de l'autre, j'ai eu deux erreurs du type -

ne peut pas trouver la déclaration de protocole pour "BDelegate", qui montrait en A.h (où j'ai écrit) ne peut pas trouver la déclaration de protocole pour "ADelegate", qui montrait en B.h (où j'ai écrit)

En regardant en ligne, les gens avaient écrit plus tôt que l'inclusion circulaire de fichiers d'en-tête pouvait entraîner des problèmes. Ils ont recommandé d'utiliser #include à la place, ou @class déclaration comme -

@class A

au lieu de

#import A.h

à l'intérieur #import B.h

J'ai essayé presque toutes les combinaisons de ces importations et @classes, et #include mais ne peut toujours pas se débarrasser des avertissements. De plus, les solutions en ligne recommandaient de déplacer le #import au .m fichiers mais cela n'a pas aidé non plus. Une partie de la raison est que les solutions en ligne sont un peu floues - si vous pouviez les décomposer, ce serait formidable.

Des suggestions sur ce qui peut être fait pour résoudre ce problème?


- 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
59
Ak1

Permettez-moi de réduire encore plus l'échantillon et d'étiqueter les lignes:

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

Considérez ce qui se passe lorsque quelque chose #importe VC1.h: il atteint la ligne A, puis l'importation est traitée. La ligne D ne fait rien car VC1.h a déjà été importé. Ensuite, la ligne E est traitée. Ensuite, ligne F, et nous obtenons une erreur car nous ne sommes pas encore arrivés à la ligne B, donc le protocole n'est pas déclaré!

Considérez alors ce qui se passe quand quelque chose # importe VC2.h: il atteint la ligne D, puis l'importation est traitée. La ligne A ne fait rien car VC2.h a déjà été importé. Ensuite, la ligne B est traitée. Ensuite, ligne C, et nous obtenons une erreur car nous ne sommes pas encore arrivés à la ligne E, donc le protocole n'est pas déclaré!

La première étape consiste à reconsidérer si ces deux classes doivent vraiment être des délégués l'une de l'autre. Si vous pouvez briser le cycle, ce serait probablement la voie à suivre. Sinon, vous devrez restructurer vos en-têtes. La façon la plus simple est probablement de mettre les délégués dans leurs propres en-têtes:

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

Si vous effectuez le suivi des importations maintenant, vous verrez que les protocoles appropriés seront désormais toujours déclarés avant que les lignes @interface n'essaient de les utiliser.

101
Anomie

Écrivez le code de déclaration de protocole au-dessus des lignes #import, par exemple.

@protocol -----

@fin

importer ----

@interface classname ---

100
Vinner

J'ai eu presque le même problème, et je l'ai résolu grâce à la réponse ci-dessus, mais d'une manière légèrement différente.

tout ce que j'ai fait était de mettre la ligne #import après la déclaration de protocole dans le fichier d'en-tête. j'espère pouvoir vous aider. et si quelqu'un sait que c'est une mauvaise programmation pour une raison quelconque, merci de me le faire savoir

37
litov

J'ai trouvé une autre solution à ce problème car je n'aimais pas vraiment l'idée de simplement avoir des #imports entre la classe et la déclaration de protocole.

Fondamentalement, vous déplacez simplement <YourProtocolName> du fichier de classe .h à l'extension de classe du fichier .m

Donc, dans votre fichier .m, vous ajoutez

@interface YourClassName () <YourProtocolName>
@end

Je ne sais pas si c'est vraiment une bonne pratique mais cela ressemble à une solution plus propre pour éviter les cycles d'importation.

10

Essayez de placer <BaseViewControllerDelegate> ou <BigViewControllerDelegate> dans le fichier d'implémentation plutôt que dans le fichier d'en-tête. Ça va marcher.

8
coreDeviOS

J'ai suivi le correctif de déplacer le protocole avant l'importation et cela a résolu le problème ... l'importation incluait le délégué, ce qui causait le problème.

Mais alors j'ai pensé, pourquoi importais-je le délégué de toute façon? Je ne référençais pas ses propriétés et je n'appelais aucune de ses méthodes directement (c'est pour cela que le protocole déclare).

J'ai essayé de commenter l'importation du délégué et j'ai vu où l'erreur est survenue et j'ai constaté que ce que j'importais lorsque j'importais le délégué était en fait une déclaration que le délégué importait, c'est-à-dire que j'importais A (également mon délégué), A importait B, ce que j'utilisais en fait était B. Donc j'ai laissé l'importation de A commentée et ajouté une importation pour B. Ensuite, je pouvais remettre l'ordre du protocole d'importation tel qu'il était.

3
dawid