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
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.
Écrivez le code de déclaration de protocole au-dessus des lignes #import, par exemple.
@fin
@interface classname ---
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
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.
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.
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.