45 votes

Pourquoi doit-on faire [classe MyClass] en Objective-C ?

En Objective-C, vous pouvez invoquer des méthodes de classe avec :

[MyClass aClassMethod];

Et vous pouvez interroger le type d'une instance avec :

[someInstance isKindOfClass:[MyClass class]];

Mais, pourquoi avons-nous besoin de faire [MyClass class] et ne pas simplement fournir MyClass comme ça :

[someInstance isKindOfClass:MyClass];

Y a-t-il une raison pour que le compilateur accepte de rencontrer MyClass comme récepteur (un type de pointeur) mais pas comme argument ? S'agit-il d'une limitation de l'analyse syntaxique du langage ? Ou peut-être une limitation du compilateur ?

42voto

bbum Points 124887

Ooooh... question amusante. La réponse est un c-isme.

Pensez-y :

@interface MyClass : NSObject
@end
@implementation MyClass
@end

Maintenant, disons que vous l'avez fait :

...
MyClass *m = nil;
...

Dans ce contexte, le compilateur voit MyClass comme définition de type. Le site * dit que la variable m est un pointer to a hunk o' memory that contains one (or many -- don't forget your C pointer-fu) MyClass instances .

En d'autres termes, MyClass est un type.

Mais, dans le contexte de quelque chose comme :

[someInstance isKindOfClass: x ];

x doit être une rvalue ou, en termes humains, la valeur d'une expression . Un type, cependant, ne peut pas être utilisé comme une rvalue.

Ce [MyClass class] est en fait un peu un hack, à la fois dans le langage et dans le compilateur, car la grammaire permet spécifiquement à un nom de type d'être le récepteur du message (d'être la cible d'un appel de méthode).

Et, en fait, vous pouvez le faire :

typedef MyClass Foo;
....
[MyClass class];
[Foo Class];

Ça va marcher. Cependant, vous ne pouvez pas faire ce qui suit mais le message d'erreur est allumé :

[NSUInteger class];

error : 'NSUInteger' n'est pas un nom de classe ou un alias en Objective-C


Maintenant, pourquoi ne pas le mettre en cas spécial partout comme un nom nu ?

Cela mélange les noms de types et les valeurs r et vous finissez rapidement par devoir avaler quelque chose comme [foo isKindOfClass: (MyClass)]; en vomissant sur [foo isKindOfClass: (MyClass *)]; ce qui empiète sur le terrain des stéréotypes d'une manière plutôt inconfortable.

7voto

yehnan Points 2011

Intéressant.

En Objective-C, le nom d'une classe a deux rôles, celui de type de données et celui d'objet de classe. En tant que nom de type de données, vous pouvez faire des choses comme :

MyClass *anObject;

En tant qu'objet de classe, le nom de la classe ne peut représenter l'objet de classe qu'en tant que récepteur de messages. Et c'est pourquoi vous devez utiliser

... isKindOfClass:[MyClass class] ...

Cependant, je ne pense pas que ce soit la réponse qui puisse satisfaire votre besoin. Pour moi, la réponse est "oui, ce que vous voulez est plausible. Mais la spécification dit le contraire".

Référence : Le langage de programmation Objective-C Page 32, section : "Noms de classes dans le code source" .

2voto

Jared Pochtar Points 3240

@John et @ryanprayogo -- vous avez tous deux fondamentalement tort. MyClass est une classe, qui est aussi un objet, mais qui n'hérite pas de NSObject. Objective-C est un peu bizarre de cette façon, mais il est en fait brillant lorsqu'il est complètement expliqué (Voir aquí ). La réponse ici, cependant, est comme @yehnan a dit, qu'un nom de classe peut être soit un nom de type pour les déclarateurs et les casts, ou comme un récepteur pour les messages. L'implémentation de [MyClass class] renvoie self (qui est, dans la méthode, MyClass). De plus, comme l'a dit @yehnan, le langage pourrait de le passer comme argument, alors qu'il ne le fait tout simplement pas.

1voto

John Biesnecker Points 2138

Ma réponse à première vue est que [MyClass class] renvoie un objet de type Class, et MyClass n'hérite pas de Class...

1voto

Rob Napier Points 92148

@yehnan l'a bien saisi, mais je vais m'étendre un peu sur le sujet. Oui, le compilateur pourrait être modifié pour convertir automatiquement l'identifiant d'une classe en son identifiant applicable Class dans les endroits où il est un argument plutôt que seulement lorsqu'il est la cible d'un message. Mais il n'y a pas beaucoup d'intérêt pour ce genre de complexité supplémentaire dans le compilateur (traduit : plus lent, plus difficile à détecter les erreurs de codage). Vous ne devriez pas appeler des choses qui retournent Class très souvent. Si c'est le cas, alors votre modèle objet est cassé. La vérification de classe devrait être la dernière approche, désespérée, après que tout le reste ait échoué (en particulier le typage correct, puis la vérification de classe). respondsToSelector: ). Ainsi, pour ce type d'événement rare, il n'est pas très utile de compliquer le compilateur de cette manière.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X