web-dev-qa-db-fra.com

Énumération de déclaration directe dans Objective-C

J'ai des problèmes avec la visibilité de l'énumération 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.

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

Je n'ai pas besoin des valeurs énumérées réelles, sauf dans le .m fichier d'implémentation, où je peux en toute sécurité #import une façon. Alors, comment puis-je obtenir le typedef enum être reconnu dans l'en-tête?

64
Stephen Touset

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

13
Sebastian Celis

La manière la plus récente (Swift 3; mai 2017) de déclarer en avant l'énumération (NS_ENUM/NS_OPTION) dans objective-c est d'utiliser ce qui suit:

// 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 */`
44
lal

La réponse à votre question consiste à importer le fichier d'en-tête typedef ou à utiliser un type générique comme NSInteger au lieu du type enum.

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

La non-importation d'un fichier d'en-tête réduit également votre accès par inadvertance aux classes superflues.

Par exemple, supposons que vous disposez d'une classe TrackFileChanges qui suit le système de fichiers pour les modifications apportées à un fichier spécifique, et que vous disposez d'une classe CachedFile qui stocke les données mises en cache à partir 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 à l'aide du nouveau runtime, mais ce n'est pas possible si vous '' en utilisant l'ancien temps d'exécution).

Les clients qui importent "CachedFile.h" n'ont donc probablement pas besoin ou ne veulent pas accéder à TrackFileChanges.h. Et s'ils le font, ils devraient le préciser en #important eux-mêmes. En utilisant @class TrackFileChanges instea de #import "TrackFileChanges.h" dans CachedFile.h vous améliorez l'encapsulation.

Mais cela dit, il n'y a rien de mal à importer un fichier d'en-tête à partir d'un deuxième fichier d'en-tête si le deuxième en-tête veut exposer le premier à tous les clients. Par exemple, les fichiers d'en-tête qui déclarent les classes doivent être importés directement dans les fichiers d'en-tête de sous-classe, et les fichiers d'en-tête déclarant les protocoles peuvent bien être importés directement (bien que vous puissiez utiliser @protocol ABC; pour éviter cela).

15
Peter N Lewis

Si vous êtes d'accord avec 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) {

}

Remarque: Cela déclenchera un -Wpedantic avertissement.


Si vous utilisez C++ 11, vous devez utiliser leurs énumérations, qui peuvent être déclarées en toute sécurité - par exemple enum class Enum:uint8_t; (pas une extension de compilateur).

4
justin

Ce qui a fonctionné pour une déclaration en avant d'une énumération pour moi dans un fichier Objective C .h était de regarder dans le fichier ProjectName-Swift.h et de voir ce qu'il contenait, qui se trouvait être le suivant:

enum SwiftEnumName: NSInteger;

J'avais besoin de cette déclaration avant car j'avais un type de paramètre de fonction SwiftEnumName. Et cela ne me permettrait pas de placer l'importation ProjectName-Swift.h dans le fichier Objective C. .h.

Ensuite, dans le fichier Objective C .m, j'avais juste le #import "ProjectName-Swift.h" et j'ai juste utilisé le SwiftEnum normalement.

Cela utilisait Swift 4.1.2.

1
Doug Voss