J'ai vu un certain nombre de stratégies pour déclarer des méthodes semi-privées en Objective-C , mais il ne semble pas y avoir de moyen de créer une méthode vraiment privée. Je reconnais que. Mais pourquoi est-ce ainsi? Chaque explication que j'ai dit essentiellement, "vous ne pouvez pas le faire, mais voici une approximation proche."
Il y a un certain nombre de mots - clés appliqués aux ivars
(membres) qui contrôlent leur champ d' application, par exemple @private
, @public
, @protected
. Pourquoi cela ne peut-il pas être fait pour les méthodes également? Il semble que le runtime devrait pouvoir prendre en charge. Y a-t-il une philosophie sous-jacente qui me manque? Est-ce délibéré?
objective-c
objective-c-runtime
Rob Jones
la source
la source
Réponses:
La réponse est ... eh bien ... simple. Simplicité et cohérence, en fait.
Objective-C est purement dynamique au moment de l'envoi de la méthode. En particulier, chaque envoi de méthode passe par le même point de résolution de méthode dynamique que chaque autre envoi de méthode. Au moment de l'exécution, chaque implémentation de méthode a exactement la même exposition et toutes les API fournies par le runtime Objective-C qui fonctionnent avec des méthodes et des sélecteurs fonctionnent de la même manière dans toutes les méthodes.
Comme beaucoup l'ont répondu (ici et dans d'autres questions), les méthodes privées à la compilation sont supportées; si une classe ne déclare pas une méthode dans son interface accessible au public, alors cette méthode pourrait tout aussi bien ne pas exister en ce qui concerne votre code. En d'autres termes, vous pouvez obtenir toutes les différentes combinaisons de visibilité souhaitées au moment de la compilation en organisant votre projet de manière appropriée.
Il y a peu d'avantages à dupliquer la même fonctionnalité dans le runtime. Cela ajouterait énormément de complexité et de frais généraux. Et même avec toute cette complexité, cela n'empêcherait toujours pas tous les développeurs, sauf les plus occasionnels, d'exécuter vos méthodes supposées "privées".
Faire ainsi, cependant, minerait la nature dynamique pure de la langue. Chaque envoi de méthode ne passerait plus par un mécanisme d'envoi identique. Au lieu de cela, vous vous retrouveriez dans une situation où la plupart des méthodes se comportent d'une manière et une petite poignée est simplement différente.
Cela va au-delà du runtime car il existe de nombreux mécanismes dans Cocoa basés sur le dynamisme cohérent d'Objective-C. Par exemple, le codage des valeurs clés et l'observation des valeurs clés devraient soit être très fortement modifiés pour prendre en charge les méthodes privées - très probablement en créant une faille exploitable - ou les méthodes privées seraient incompatibles.
la source
Le runtime pourrait le supporter mais le coût serait énorme. Chaque sélecteur envoyé devrait être vérifié pour savoir s'il est privé ou public pour cette classe, ou chaque classe devrait gérer deux tables de répartition distinctes. Ce n'est pas la même chose pour les variables d'instance car ce niveau de protection est effectué au moment de la compilation.
En outre, le moteur d'exécution doit vérifier que l'expéditeur d'un message privé est de la même classe que le destinataire. Vous pouvez également contourner les méthodes privées; si la classe utilisée
instanceMethodForSelector:
, elle pourrait donner le retourIMP
à n'importe quelle autre classe pour qu'ils invoquent directement la méthode privée.Les méthodes privées n'ont pas pu contourner l'envoi du message. Considérez le scénario suivant:
Une classe
AllPublic
a une méthode d'instance publiquedoSomething
Une autre classe
HasPrivate
a une méthode d'instance privée également appeléedoSomething
Vous créez un tableau contenant n'importe quel nombre d'instances des deux
AllPublic
etHasPrivate
Vous avez la boucle suivante:
Si vous exécutiez cette boucle de l'intérieur
AllPublic
, le runtime devrait vous empêcher d'envoyerdoSomething
sur lesHasPrivate
instances, mais cette boucle serait utilisable si elle était à l'intérieur de laHasPrivate
classe.la source
Les réponses publiées jusqu'à présent permettent de bien répondre à la question d'un point de vue philosophique, je vais donc poser une raison plus pragmatique: que gagnerait-il à changer la sémantique du langage? C'est assez simple pour "cacher" efficacement les méthodes privées. À titre d'exemple, imaginez que vous ayez une classe déclarée dans un fichier d'en-tête, comme ceci:
Si vous avez besoin de méthodes "privées", vous pouvez également les mettre dans le fichier d'implémentation:
Bien sûr, ce n'est pas tout à fait la même chose que les méthodes privées C ++ / Java, mais c'est en fait assez proche, alors pourquoi modifier la sémantique du langage, ainsi que le compilateur, le runtime, etc., pour ajouter une fonctionnalité déjà émulée dans un format acceptable façon? Comme indiqué dans d'autres réponses, la sémantique de passage des messages - et leur dépendance à la réflexion d'exécution - rendrait la gestion des messages "privés" non triviale.
la source
La solution la plus simple consiste simplement à déclarer certaines fonctions C statiques dans vos classes Objective-C. Celles-ci ont uniquement une portée de fichier selon les règles C pour le mot clé static et à cause de cela, elles ne peuvent être utilisées que par les méthodes de cette classe.
Pas de problème du tout.
la source
Oui, cela peut être fait sans affecter le runtime en utilisant une technique déjà employée par le (s) compilateur (s) pour gérer C ++: la gestion des noms.
Cela n'a pas été fait parce qu'il n'a pas été établi que cela résoudrait une difficulté considérable dans l'espace des problèmes de codage que d'autres techniques (par exemple, le préfixe ou le soulignement) sont capables de contourner suffisamment. IOW, vous avez besoin de plus de douleur pour surmonter les habitudes enracinées.
Vous pouvez apporter des correctifs à clang ou gcc qui ajoutent des méthodes privées à la syntaxe et génèrent des noms mutilés qu'il a seuls reconnus lors de la compilation (et oubliés rapidement). Ensuite, d'autres membres de la communauté Objective-C seraient en mesure de déterminer si cela en valait la peine ou non. Cela sera probablement plus rapide que d'essayer de convaincre les développeurs.
la source
Essentiellement, cela a à voir avec la forme d'appels de méthode de transmission de messages d'Objective-C. N'importe quel message peut être envoyé à n'importe quel objet, et l'objet choisit comment répondre au message. Normalement, il répondra en exécutant la méthode nommée d'après le message, mais il pourrait également répondre de plusieurs autres manières. Cela ne rend pas les méthodes privées complètement impossibles - Ruby le fait avec un système de transmission de messages similaire - mais cela les rend quelque peu gênantes.
Même l'implémentation de méthodes privées par Ruby est un peu déroutante pour les gens à cause de l'étrangeté (vous pouvez envoyer à l'objet n'importe quel message que vous aimez, sauf ceux de cette liste !). Essentiellement, Ruby le fait fonctionner en interdisant aux méthodes privées d'être appelées avec un récepteur explicite. En Objective-C, cela nécessiterait encore plus de travail car Objective-C n'a pas cette option.
la source
C'est un problème avec l'environnement d'exécution d'Objective-C. Alors que C / C ++ se compile en code machine illisible, Objective-C conserve toujours certains attributs lisibles par l'homme comme les noms de méthodes sous forme de chaînes . Cela donne à Objective-C la possibilité d'exécuter des fonctions réfléchissantes .
EDIT: Être un langage réflexif sans méthodes privées strictes rend Objective-C plus "pythonique" en ce sens que vous faites confiance aux autres personnes qui utilisent votre code plutôt que de restreindre les méthodes qu'elles peuvent appeler. L'utilisation de conventions de dénomination telles que les doubles traits de soulignement vise à masquer votre code à un codeur client occasionnel, mais n'empêchera pas les codeurs de faire un travail plus sérieux.
la source
Il y a deux réponses selon l'interprétation de la question.
La première consiste à masquer l'implémentation de la méthode de l'interface. Ceci est utilisé, généralement avec une catégorie sans nom (par exemple
@interface Foo()
). Cela permet à l'objet d'envoyer ces messages mais pas d'autres - bien que l'on puisse toujours les remplacer accidentellement (ou autrement).La deuxième réponse, en supposant qu'il s'agit de performances et d'inlining, est rendue possible mais en tant que fonction C locale à la place. Si vous vouliez une
NSString *arg
méthode 'private foo ( )', vous la feriezvoid MyClass_foo(MyClass *self, NSString *arg)
et l'appeliez comme une fonction C commeMyClass_foo(self,arg)
. La syntaxe est différente, mais elle agit avec le type sain de caractéristiques de performance des méthodes privées de C ++.Bien que cela réponde à la question, je dois souligner que la catégorie sans nom est de loin la manière la plus courante d'Objective-C de le faire.
la source
Objective-C ne prend pas en charge les méthodes privées car il n'en a pas besoin.
En C ++, chaque méthode doit être visible dans la déclaration de la classe. Vous ne pouvez pas avoir de méthodes que quelqu'un incluant le fichier d'en-tête ne peut pas voir. Donc si vous voulez des méthodes que le code en dehors de votre implémentation ne doit pas utiliser, vous n'avez pas le choix, le compilateur doit vous donner un outil pour que vous puissiez lui dire que la méthode ne doit pas être utilisée, c'est le mot clé "private".
En Objective-C, vous pouvez avoir des méthodes qui ne sont pas dans le fichier d'en-tête. Vous atteignez donc très facilement le même objectif en n'ajoutant pas la méthode au fichier d'en-tête. Il n'y a pas besoin de méthodes privées. Objective-C a également l'avantage que vous n'avez pas besoin de recompiler chaque utilisateur d'une classe car vous avez changé les méthodes privées.
Par exemple, les variables que vous deviez déclarer dans le fichier d'en-tête (plus maintenant), @private, @public et @protected sont disponibles.
la source
Une réponse manquante ici est: parce que les méthodes privées sont une mauvaise idée du point de vue de l'évolutivité. Cela peut sembler une bonne idée de rendre une méthode privée lors de son écriture, mais c'est une forme de liaison précoce. Le contexte peut changer et un utilisateur ultérieur peut souhaiter utiliser une implémentation différente. Un peu provocateur: "Les développeurs agiles n'utilisent pas de méthodes privées"
D'une certaine manière, tout comme Smalltalk, Objective-C est destiné aux programmeurs adultes. Nous apprécions de savoir ce que le développeur d'origine a supposé que l'interface devrait être, et nous prenons la responsabilité de gérer les conséquences si nous devons modifier l'implémentation. Alors oui, c'est de la philosophie, pas de la mise en œuvre.
la source