2009-11-27 3 views
9

Est-il possible de découvrir à l'exécution quelles sous-classes existent d'une classe donnée?Découvrez les sous-classes d'une classe donnée dans Obj-C

Editer: Depuis les réponses jusqu'à présent, je pense que je dois clarifier un peu plus ce que je suis en train de faire. Je suis conscient que ce n'est pas une pratique courante dans le cacao, et que cela peut comporter quelques réserves.

J'écris un analyseur en utilisant le modèle de création dynamique. (Voir le livre Cocoa Design Patterns de Buck et Yacktman, chapitre 5.) Fondamentalement, l'instance de l'analyseur traite une pile et instancie des objets qui savent comment effectuer certains calculs.

Si je peux obtenir toutes les sous-classes de la classe MYCommand, je peux, par exemple, fournir à l'utilisateur une liste de commandes disponibles. De plus, dans l'exemple du chapitre 5, l'analyseur a un dictionnaire de substitution, ce qui permet d'utiliser des opérateurs comme +, -, * et /. (Ils sont mappés à MYAddCommand, etc.) Pour moi, il semblait que cette information appartenait à la sous-classe MyCommand, pas l'instance de l'analyseur, car elle va un peu à l'encontre de l'idée de création dynamique.

Répondre

13

Plutôt que d'essayer d'enregistrer automatiquement toutes les sous-classes de MYCommand, pourquoi ne pas diviser le problème en deux?

D'abord, fournissez l'API pour enregistrer une classe, quelque chose comme +[MYCommand registerClass:]. Ensuite, créez du code dans MYCommand, ce qui signifie que toutes les sous-classes s'enregistreront automatiquement. Quelque chose comme:

@implementation MYCommand 
+ (void)load 
{ 
    [MYCommand registerClass:self]; 
} 
@end 
+0

Cela ressemble à la bonne façon d'aller en effet. D'autant plus que la documentation mentionne que la méthode '+ load' d'une classe est appelée après toutes ses méthodes '+ load'. Un grand merci aux autres personnes qui ont fourni des réponses, mais leurs réponses étaient également excellentes. –

+2

Les sous-classes de MyCommand n'appellent pas + load sur leur superclasse. + load n'est appelé que dans les classes qui l'implémentent. –

+0

Surprise il a fallu si longtemps pour que quelqu'un me corrige! Je suis généralement d'accord avec les réponses ici que l'enregistrement automatique est une mauvaise idée et devrait être traitée un peu plus manuellement à la place. –

19

Pas directement, non. Vous pouvez cependant obtenir une liste de toutes les classes enregistrées avec le moteur d'exécution et interroger ces classes pour leur superclasse direct. Gardez à l'esprit que cela ne vous permet pas de trouver tous les ancêtres de la classe dans l'arbre d'héritage, juste la superclasse immédiate.

Vous pouvez utiliser objc_getClassList() pour obtenir la liste des objets Class enregistrés avec le moteur d'exécution. Ensuite, vous pouvez faire une boucle sur ce tableau et appeler le [NSObject superclass] sur ces objets Class pour obtenir l'objet Class de leur superclasse. Si, pour une raison quelconque, vos classes n'utilisent pas NSObject comme classe racine, vous pouvez utiliser class_getSuperclass() à la place.

Je devrais également mentionner que vous pourrait penser incorrectement à la conception de votre application si vous estimez qu'il est nécessaire de faire ce genre de découverte. Très probablement, il existe une autre façon plus conventionnelle de faire ce que vous essayez d'accomplir qui n'implique pas l'introspection sur l'exécution d'Objective-C. Marc et bbum l'ont frappé sur l'argent.

+7

Je le dirais plus fortement; Si vous pensez que vous avez besoin de faire cela dans le code de production, vous avez très probablement très mal fait.L'introspection de l'héritage à la baisse est extrêmement rare et c'est la raison pour laquelle le moteur d'exécution ne le supporte pas directement. Qu'essayez-vous de faire? – bbum

+0

@bbum J'ai ajouté une description de ce que j'essaie de faire. Pensez-vous toujours que je le fais très très mal? J'ai du mal à penser à une autre façon de le faire sans chercher des sous-classes. –

4

Ce n'est généralement pas une bonne idée.

Cependant, nous avons un code sur notre wiki CocoaHeads qui fait cela: http://cocoaheads.byu.edu/wiki/getting-all-subclasses

+1

Une autre mise en garde; Lorsque vous faites ce genre de chose, vous finirez par provoquer l'initialisation des classes dans un ordre qui n'a jamais été initialisé auparavant. Cela ne devrait pas causer de problèmes, mais parfois en raison de dépendances dans les classes système qui peuvent changer entre les versions ... – bbum

+0

La description du code lié spécifiquement dit que cette approche n'appelle pas '+ initialize', et bien que je n'aie pas Je n'ai pas encore essayé, semble-t-il. –

0

Il y a un code dans mon projet de navigateur d'exécution here qui comprend un -subclassNamesForClass: méthode. Voir les fichiers RuntimeReporter.[hm].

+0

Merci, c'est un outil intéressant à ajouter à ma ceinture. Bien que je vais aller avec l'approche de Mike pour ce cas particulier. –

+0

J'ai remarqué que le lien posté par @NSResponder est cassé. Pour ceux qui cherchent un moyen de parcourir une hiérarchie de classes, j'ai écrit un [Class Hierarchy Logger] (https://github.com/sebaven/class-hierarchy-logger) qui utilise une approche similaire. Cela peut être utile si vous avez besoin de plus d'informations sur la procédure d'itération de la hiérarchie de sous-classes. J'espère que ça aide! –

3

Une autre approche vient d'être publiée par Matt Gallagher au his blog.

Questions connexes