2009-06-03 14 views
47

Je rencontre des problèmes avec la visibilité enum dans un programme Objective-C. J'ai deux fichiers d'en-tête, et l'un définit un typedef enum. Un autre fichier doit utiliser le type typedef 'd.Énoncé de déclaration avancée dans Objective-C

En C droite, je voudrais simplement #include l'autre fichier d'en-tête, mais en Objective-C, il est recommandé de ne pas utiliser #import entre les fichiers d'en-tête, au lieu d'utiliser avant @class déclarations au besoin. Cependant, je ne peux pas comprendre comment déclarer un type d'énumération.

Je n'ai pas besoin des valeurs énumérées réelles, sauf dans le fichier d'implémentation .m correspondant, où je peux #import loin. Alors, comment puis-je obtenir le typedef enum à reconnaître dans l'en-tête?

+0

Pour toute réponse récente (Swift 3, 2017) chercher à ma réponse. http://stackoverflow.com/a/42009056/342794 – lal

Répondre

18

Allez-y et utilisez #import. La seule raison pour laquelle les gens recommandent d'utiliser @class lorsque c'est possible est parce que cela rend votre code légèrement plus rapide à compiler. Cependant, il n'y a aucun problème avec #import un fichier .h d'un autre. En fait, vous devez le faire lorsque vous étendez une autre classe.

+1

Y a-t-il un moyen de faire cela sans utiliser #import? Que diriez-vous simplement de faire un 'typedef int EnumName'? –

+1

Je ne pense pas. Voir le lien dans la réponse de gs: http://stackoverflow.com/questions/71416/forward-declaring-an-enum-in-c –

+0

AveC#import la compilation nécessite des minutes, et il y a quelque chose de câblé de toute façon. –

0

De toute façon, vous devrez #import ou créer un fichier d'en-tête distinct contenant uniquement le typedef. Ne pas importer les fichiers d'en-tête dans un en-tête accélère la compilation, mais ne change rien d'autre.

Why doesn't C++ support forward declaration of enums?

16

La réponse à votre question est soit aller de l'avant et importer le fichier d'en-tête de typedef ou d'utiliser un type générique comme NSInteger au lieu du type ENUM.

Toutefois, il y a plus de raison de ne pas importer de fichier d'en-tête que de simplement compiler la vitesse.

L'importation d'un fichier d'en-tête réduit également votre accès par inadvertance aux classes superflues. Par exemple, supposons que vous ayez une classe TrackFileChanges qui suit le système de fichiers pour les modifications apportées à un fichier spécifique et que vous avez une classe CachedFile qui stocke les données mises en cache d'un fichier. Ce dernier peut utiliser un ivar privé de type TrackFileChanges *, mais pour les utilisations de CachedFile, il s'agit simplement d'un détail d'implémentation (idéalement, l'ivar serait généré automatiquement avec une propriété privée utilisant le nouveau runtime, mais ce n'est pas possible si vous re en utilisant l'ancien temps d'exécution). Par conséquent, les clients qui #importent "CachedFile.h" n'ont probablement pas besoin ou ne veulent pas accéder à TrackFileChanges.h. Et s'ils le font, ils devraient le clarifier en l'important eux-mêmes. En utilisant @class TrackFileChanges instea de #import "TrackFileChanges.h" dans CachedFile.h vous améliorez l'encapsulation. Mais tout cela dit, il n'y a rien d'important à importer un fichier d'en-tête d'un second fichier d'en-tête si le second en-tête veut exposer le premier à tous les clients. Par exemple, les fichiers d'en-tête qui déclarent des classes doivent être importés directement dans des fichiers d'en-tête de sous-classe, et les fichiers d'en-tête déclarant des protocoles peuvent être importés directement (bien que vous puissiez utiliser @protocol ABC pour éviter cela).

4

Si vous êtes ok en utilisant les extensions du compilateur, vous pouvez utiliser cet ordre dans Clang:

enum Enum; 
typedef enum Enum Enum2; 

void f(Enum2); // ok. it sees this type's true name. 

enum Enum { 
    E_1 
}; 

// ok. now its declaration is visible and we can use it. 

void f(Enum2 e) { 

} 

Note: Il déclenche un avertissement -Wpedantic.


Si vous utilisez 11 C++, vous devez utiliser leurs énumérations, qui sont sûrs de transmettre déclarer - par exemple enum class Enum:uint8_t; (pas une extension de compilateur).

+1

Vous pouvez simplifier cette réponse à ceci: 'typedef enum Enum Enum;' Ensuite, utilisez simplement Enum dans la définition et la déclaration de votre méthode. –

15

Le plus récent chemin (Swift 3, mai 2017) de transmettre déclarer la ENUM (NS_ENUM/NS_OPTION) en c objectif est d'utiliser les éléments suivants:

// Forward declaration for XYZCharacterType in other header say XYZCharacter.h 
typedef NS_ENUM(NSUInteger, XYZCharacterType); 


// Enum declaration header: "XYZEnumType.h" 
#ifndef XYZCharacterType_h 
#define XYZCharacterType_h 

typedef NS_ENUM(NSUInteger, XYZEnumType) { 
    XYZCharacterTypeNotSet, 
    XYZCharacterTypeAgent, 
    XYZCharacterTypeKiller, 
}; 

#endif /* XYZCharacterType_h */` 
+1

travaillé pour moi avec swift 3 – stringRay2014

+3

De nos jours, cela devrait être la réponse acceptée – citxx

+1

J'ai commencé à regarder typedef NS_ENUM seulement hier comme un moyen de nettoyer l'ancien code Objective C - et cette réponse a fonctionné pour moi. – Greg