Problème de références croisées sur delegates

muqaddarmuqaddar Administrateur
février 2011 modifié dans Objective-C, Swift, C, C++ #1
Depuis quelques temps, j'ai quelques soucis de compilation suite à  des imports de classes qui contiennent des délégués. A vrai dire, je ne sais pas si c'est un problème logique... ou si c'est Xcode 4.0 qui a un soucis.

Fichier VinocellaViewController.h

#import &quot;CountriesViewController.h&quot;<br /><br />@protocol SearchDataSource<br /><br />- (NSUInteger)countryId;<br />- (void)setCountryId:(NSUInteger)aCountryId;<br /><br />@end<br /><br />@interface VinocellaViewController : UIViewController &lt;SearchDataSource,&nbsp; CountriesViewControllerDelegate&gt;<br />{<br />}<br />@end


Fichier CountriesViewController.h

#import &quot;ReferenceViewController.h&quot;<br />#import &quot;VinocellaViewController.h&quot;<br /><br />@protocol CountriesViewControllerDelegate<br />@optional<br />- (void)dismissCurrentPopover:(UIPopoverController*)aPopoverController;<br />@end<br /><br />@interface CountriesViewController : UIViewController<br />{<br />	id&lt;ReferenceDataSource&gt; referenceDataSource;<br />	id&lt;SearchDataSource&gt; searchDataSource;<br />&nbsp; <br />	id&lt;CountriesViewControllerDelegate&gt; delegate;<br />	UIPopoverController *popoverController;<br />}


Et, à  partir du moment où j'importe ce fameux CountriesViewController.h dans VinocellaViewController.h, je me tape ce genre d'erreurs (cf capture) En gros, beaucoup de classe qui importent VinocellaViewController.h pètent un plomb... et ne trouvent plus le SearchDataSource qui est bien importé dans ces classes.

Sauf que pour implémenter mon mécanisme de delegate lié à  CountriesViewController, je suis obligé d'importer le .h n'est-ce pas ?
Car @class CountriesViewController; ne permet pas de faire reconnaà®tre le protocole créé dans CountriesViewController...



Réponses

  • zoczoc Membre
    21:45 modifié #2
    Les forward declaration, ça marche également pour les protocoles ;)


    Donc dans VinocellaViewController.h:


    <br />...<br />@protocol CountriesViewControllerDelegate;<br />...<br />@interface VinocellaViewController : UIViewController &lt;SearchDataSource,&nbsp; CountriesViewControllerDelegate&gt;<br />...
    
  • muqaddarmuqaddar Administrateur
    21:45 modifié #3
    dans 1298285382:

    Les forward declaration, ça marche également pour les protocoles ;)


    Oh purée !  :o
    Je l'avais jamais vu auparavant ou n'y avais pas fait attention !  >:)
    Merci zoc.
  • AliGatorAliGator Membre, Modérateur
    21:45 modifié #4
    Oui ou alors tu fais l'inverse (forward declaration, mais de la classe ("@class VinocellaViewController;" dans CountriesViewController), ça marche aussi. Le principal c'est de ne pas avoir des références croisées dans tes #imports (A.h qui #import "B.h" et ce B.h qui #import lui-même "A.h", comme dans ton cas)
  • muqaddarmuqaddar Administrateur
    février 2011 modifié #5
    dans 1298292057:

    Oui ou alors tu fais l'inverse (forward declaration, mais de la classe ("@class VinocellaViewController;" dans CountriesViewController)


    De la classe ?
    Du protocole tu veux dire non ? Tu m'as un peu perdu là .  :(
  • AliGatorAliGator Membre, Modérateur
    21:45 modifié #6
    Oui non en fait je n'avais pas regardé ton code en détail. Vu comment tu as mixé les @protocol et les @interface dans tes fichiers, et pas fait un fichier par @protocol ; et par @interface ni surtou n'utilisé ton @protocol que finalement à  un seul endroit, du coup en effet seule la solution de zoc est valable dans ce sens.

    Sinon tu fais un DataSourceProtocol.h dans lequel tu mets juste ton @protocol, et tu #import "DataSourceProtocol.h" à  la fois dans ton "VinocellaViewController.h", mais aussi dans ton "CountriesViewController.h" (dans lequel tu n'aurais plus à  faire #import "VinocellaViewController.h" du coup).
    Parce que là  ça m'a l'air un peu fouilli de déclarer un @protocol dans le même fichier qu'une autre classe alors que ce protocol n'est pas utilisé QUE par cette classe. Autant pour le "CountriesViewControllerDelegate" ça se justifie tout à  fait de le mettre dans le même fichier que la classe CountriesViewController elle-même, autant pour ton SearchDataSource qui est utilisé à  divers endroit je suis pas sûr que ça soit pas plus clair et propre de le mettre à  part, surtout si dans l'autre fichier "CountriesViewController.h" tu ne fais le #import "VinocellaViewController.h"... QUE pour importer ce SearchDataSource sans avoir besoin de la classe VinocellaViewController à  cet endroit.
  • muqaddarmuqaddar Administrateur
    21:45 modifié #7
    dans 1298292835:

    Sinon tu fais un DataSourceProtocol.h dans lequel tu mets juste ton @protocol, et tu #import "DataSourceProtocol.h" à  la fois dans ton "VinocellaViewController.h", mais aussi dans ton "CountriesViewController.h" (dans lequel tu n'aurais plus à  faire #import "VinocellaViewController.h" du coup).


    Effectivement, je ne l'ai jamais fait (mettre un protocole dans un fichier à  part), et j'avoue que ça éclaircirait encore le code, sa compréhension, et la compréhension des imports !

    Merci ! (super content de structurer de plus en plus mon code sur des applis conséquentes)
  • muqaddarmuqaddar Administrateur
    21:45 modifié #8
    D'ailleurs, dans mes protocoles, j'ai souvent des méthodes Delegate et Datasource.

    Et comme je suis fainéant, je me contente de les appeler DataSource et de ne faire qu'un protocole au lieu de 2 pour ne pas avoir ensuite à  en importer 2 dans les classes qui en ont besoin...  >:)
  • muqaddarmuqaddar Administrateur
    21:45 modifié #9
    C'est pas encore tout à  fait ça.

    Bien que tout a l'air de marcher, je me tape des warnings étranges.

    #import &quot;SearchDataSourceProtocol.h&quot;<br /><br />@protocol PADBUpdateControllerDelegate;<br />@protocol CountriesViewControllerDelegate;<br />@protocol ItemsViewControllerDelegate;<br /><br />@interface VinocellaViewController : UIViewController <br />&lt;SearchDataSource, <br />PADBUpdateControllerDelegate, <br />CountriesViewControllerDelegate, <br />ItemsViewControllerDelegate&gt;
    


    No definition of protocol 'PADBUpdateControllerDelegate' is found
    No definition of protocol 'CountriesViewControllerDelegate' is found
    No definition of protocol 'ItemsViewControllerDelegate' is found
  • AliGatorAliGator Membre, Modérateur
    21:45 modifié #10
    Tu fais quand même un #import (du fichier contenant la définition du protocol) dans ton ".m" au moins ?
    Les forward declarations c'est bien, mais faut quand même qu'il ait les définitions à  un moment donné, surtout dans l'implémentation, pour vérifier que tu as bien implémenté toutes les méthodes @required du protocole, etc !
  • muqaddarmuqaddar Administrateur
    21:45 modifié #11
    Oui, bien sûr, j'ai fait les imports nécessaires dans le .m.

    Je sèche depuis quelques heures (et je répète que tout marche pourtant), mais je déteste les warnings...

  • muqaddarmuqaddar Administrateur
    mars 2011 modifié #12
    Au fait, j'ai toujours pas réglé mon soucis d'import de delegates et de warnings...
    cf capture.

    Pour le coup, je vais finir par me demander si c'est pas Xcode 4 qui a un plomb dans l'aile.
    (je précise à  nouveau que tout tourne comme une horloge dans l'app)

  • AliGatorAliGator Membre, Modérateur
    21:45 modifié #13
    Bah non c'est normal le warning qu'il te met.
    Tu lui indiques que ta classe implémente le protocole A (en la mettant dans les chevrons <...>), mais quand il voit ça lui il a besoin de savoir en détail à  quoi correspond ce @protocol, plus que son nom mais bien quelles sont les méthodes que ta classe va devoir implémenter pour se rendre conforme à  ce protocole.
    Or ça tu ne lui as mis nulle part, puisque tu n'as indiqué que la (forward-)déclaration de ton @protocol, mais pas sa définition (avec sa liste de méthodes) !
  • muqaddarmuqaddar Administrateur
    21:45 modifié #14
    dans 1298992584:

    Bah non c'est normal le warning qu'il te met.
    Tu lui indiques que ta classe implémente le protocole A (en la mettant dans les chevrons <...>), mais quand il voit ça lui il a besoin de savoir en détail à  quoi correspond ce @protocol, plus que son nom mais bien quelles sont les méthodes que ta classe va devoir implémenter pour se rendre conforme à  ce protocole.
    Or ça tu ne lui as mis nulle part, puisque tu n'as indiqué que la (forward-)déclaration de ton @protocol, mais pas sa définition (avec sa liste de méthodes) !


    Donc il fait que j'importe le .h où se trouvent les listes de méthodes ? (du coup je reviens un peu au problème du début de mon sujet, bien que je ne l'ai plus puisque j'ai créé des fichiers à  part pour mes 2 principaux protocoles)
  • AliGatorAliGator Membre, Modérateur
    21:45 modifié #15
    Si tes protocoles sont utilisés par plusieurs classes, oui il est mieux de les extraire dans des fichiers séparés comme ça dans chaque classe où tu as besoin du @protocol tu peux n'inclure que le .h contenant le protocole.

    A mon avis c'est la (seule) solution à  ton problème vu que tes protocoles sont un peu génériques (et pas fortement liés à  la classe comme ça peut être le cas pour un UITableView et son UITableViewDataSource ou UITableViewDelegate, dans ton cas tu utilises ton protocol pour d'autres classes aussi c'est là  toute la différence) et utilisés par diverses classes, il faut cloisonner.
Connectez-vous ou Inscrivez-vous pour répondre.