Question

Je l'ai vu un certain nombre de stratégies pour déclarer des méthodes semi-privées dans Objective-C , mais il ne semble pas être un moyen de faire une méthode vraiment privée. Je reconnais que. Mais, pourquoi il en est ainsi? Chaque explication que j'ai dit essentiellement, « vous ne pouvez pas le faire, mais voici une bonne approximation. »

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 ne peut-il être fait pour les méthodes aussi bien? Il semble que quelque chose que le temps d'exécution devrait être en mesure de soutenir. Y at-il une philosophie sous-jacente qui me manque? Est-ce délibéré?

Était-ce utile?

La solution

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 la méthode passe par le même point exact de la résolution de la méthode dynamique que tous les autres envoi de la méthode. Lors de l'exécution, chaque implémentation de la méthode a exactement la même exposition et toutes les API fournies par le moteur d'exécution Objective-C qui fonctionnent avec des méthodes et des sélecteurs travaillent également les mêmes pour toutes les méthodes.

Comme beaucoup ont répondu (à la fois ici et dans d'autres questions), des méthodes privées de compilation sont pris en charge; si une classe ne déclare pas une méthode dans son interface publiquement disponible, cette méthode pourrait aussi bien ne pas exister dans la mesure où votre code est concerné. En d'autres termes, vous pouvez obtenir toutes les différentes combinaisons de visibilité souhaitée au moment de la compilation en organisant votre projet de façon appropriée.

Il y a peu d'avantages pour reproduire la même fonctionnalité dans le temps d'exécution. Il ajouterait une énorme quantité de complexité et les frais généraux. Et même avec toute cette complexité, il ne serait pas empêcher tout mais le développeur le plus occasionnel d'exécuter vos soi-disant méthodes « privées ».

  

EDIT: L'une des hypothèses que j'ai   remarqué est que les messages privés seraient   passer par le moteur d'exécution   entraînant potentiellement un grand   aérien. Est-ce tout à fait vrai?

     
    

Oui, il est. Il n'y a aucune raison de supposer que la classe implementor d'une ne voudrait pas utiliser toutes les caractéristiques Objective-C défini dans la mise en œuvre, et cela signifie que l'envoi dynamique doit se produire. Cependant , il n'y a pas de raison particulière des méthodes privées ne pouvaient pas être expédiés par une variante spéciale de objc_msgSend(), puisque le compilateur sait qu'ils étaient privés; à savoir cela pourrait être réalisé par addition d'une table de procédé uniquement privé à la structure de Class.

  
     

Il n'y aurait aucun moyen pour un privé   Procédé pour court-circuiter cette vérification ou   sauter le moteur d'exécution?

     
    

Il ne pouvait pas ignorer l'exécution, mais le moteur d'exécution ne pas nécessairement faire une vérification des méthodes privées.

         

Cela dit, il n'y a aucune raison qu'un tiers ne pouvait pas appeler délibérément objc_msgSendPrivate() sur un objet, en dehors de la mise en œuvre de cet objet, et certaines choses (KVO, par exemple) devraient le faire. En effet, il serait tout simplement une convention et peu mieux dans la pratique que les sélecteurs de préfixer méthodes privées ou non les mentionner dans l'en-tête d'interface.

  

Pour ce faire, cependant, porterait atteinte à la nature pure dynamique de la langue. Ne serait plus chaque envoi de la méthode passer par un mécanisme de répartition identique. Au lieu de cela, vous seriez laissé dans une situation où la plupart des méthodes se comportent d'une façon et une petite poignée sont juste différents.

Cela va au-delà de l'exécution, car il existe de nombreux mécanismes de cacao construites sur le dynamisme constant de Objective-C. Par exemple, à la fois la valeur clé de codage et valeur de la clé d'observation devraient soit être très fortement modifiées pour soutenir des méthodes privées - très probablement en créant une faille exploitable - ou des méthodes privées seraient incompatibles

.

Autres conseils

Le temps d'exécution pourrait le soutenir, mais le coût serait énorme. Chaque sélecteur envoyé devra vérifier pour que ce soit privé ou public pour cette classe, ou chaque classe devra gérer deux tables de distribution distinctes. Ce n'est pas la même chose pour les variables d'instance, car ce niveau de protection se fait au moment de la compilation.

En outre, le moteur d'exécution aurait besoin de vérifier que l'expéditeur d'un message privé est de la même classe que le récepteur. Vous pouvez également contourner les méthodes privées; si la classe utilisée instanceMethodForSelector:, il pourrait donner le IMP retourné à une autre classe pour eux d'appeler la méthode privée directement.

Les méthodes privées ne peuvent pas contourner l'envoi de messages. Considérez le scénario suivant:

  1. A AllPublic de classe a une méthode instance publique doSomething

  2. Une autre HasPrivate de classe a une méthode d'instance privée appelée aussi doSomething

  3. Vous créez un tableau contenant un certain nombre de cas, à la fois AllPublic et HasPrivate

  4. Vous avez la boucle suivante:

    for (id anObject in myArray)
        [anObject doSomething];
    

    Si vous avez exécuté cette boucle à l'intérieur AllPublic, le moteur d'exécution aurait à vous arrêter d'envoyer doSomething sur les instances de HasPrivate, mais cette boucle serait utilisable si elle était à l'intérieur de la classe HasPrivate.

Les réponses affichées ainsi faire beaucoup un bon travail de répondre à la question d'un point de vue philosophique, donc je vais poser une raison plus pragmatique: ce que l'on gagnerait en changeant la sémantique de la langue? Il est assez simple de « cacher » efficacement des méthodes privées. A titre d'exemple, imaginez que vous avez une classe déclarée dans un fichier d'en-tête, comme suit:

@interface MyObject : NSObject {}
- (void) doSomething;
@end

Si vous avez besoin de méthodes « privées », vous pouvez aussi mettre cela dans le fichier de mise en œuvre:

@interface MyObject (Private)
- (void) doSomeHelperThing;
@end

@implementation MyObject

- (void) doSomething
{
    // Do some stuff
    [self doSomeHelperThing];
    // Do some other stuff;
}

- (void) doSomeHelperThing
{
    // Do some helper stuff
}

@end

Bien sûr, ce n'est pas tout à fait les mêmes que les méthodes privées C ++ / Java, mais il est effectivement assez proche, alors pourquoi modifier la sémantique de la langue, ainsi que le compilateur, l'exécution, etc., d'ajouter une fonctionnalité qui est déjà émulé d'une manière acceptable? Comme il est indiqué dans d'autres réponses, la sémantique de passage de messages - et leur dépendance à la réflexion d'exécution -. Rendraient le traitement des messages « privés » non-trivial

La solution la plus simple est juste de déclarer certaines fonctions statiques C dans vos classes Objective-C. Celles-ci ont seulement la portée du fichier selon les règles de C pour le mot-clé statique et de ce qu'ils ne peuvent être utilisés par des méthodes dans cette classe.

Pas de chichi du tout.

Oui, il peut être fait sans affecter l'exécution en utilisant pour le traitement C ++ une technique déjà utilisée par le compilateur (s):. Nom mangling

Il n'a pas été fait parce qu'il n'a pas été établi qu'il résoudrait des difficultés considérables dans l'espace des problèmes de codage que d'autres techniques (par exemple, Préfixez ou soulignant) sont en mesure de contourner suffisamment. OIEau, vous avez besoin plus de douleur pour surmonter les habitudes bien ancrées.

Vous pouvez contribuer à des correctifs Clang ou gcc qui ajoutent des méthodes privées à la syntaxe et les noms générés mutilées que seul reconnu lors de la compilation (et rapidement a oublié). Ensuite, d'autres dans la communauté Objective-C seraient en mesure de déterminer si elle était réellement utile ou non. Il est probablement plus rapide de cette façon que d'essayer de convaincre les développeurs.

Pour l'essentiel, il doit faire avec passage de messages de Objective-C la forme d'appels de méthode. Tout message peut être envoyé à un objet, et l'objet choisit comment répondre au message. Normalement, il répondra en exécutant la méthode nommée le message, mais il pourrait répondre dans un certain nombre d'autres façons aussi. Cela ne fait pas des méthodes privées complètement impossible - Ruby il le fait avec un système de transmission de messages similaires - mais il ne les rend quelque peu maladroit.

Même Ruby la mise en œuvre des méthodes privées est un peu déroutant pour les personnes en raison de l'étrangeté (vous pouvez envoyer l'objet tout message que vous voulez, sauf pour ceux qui figurent sur cette liste !). Essentiellement, Ruby fait fonctionner en interdisant des méthodes privées à appeler avec un récepteur explicite. En Objective-C, il faudrait encore plus de travail depuis Objective-C n'a pas cette option.

Il est un problème avec l'environnement d'exécution de l'Objective-C. Alors que C / C ++ compile vers le bas en code machine illisible , Objective-C conserve encore certains attributs lisibles par l'homme comme les noms de méthode comme des chaînes . Cela donne Objective-C la possibilité d'effectuer caractéristiques réfléchissantes .

EDIT: Être un langage réflexif sans méthodes privées strictes rend Objective-C plus « pythonique » en qui vous avez confiance d'autres personnes qui utilisent votre code plutôt que de limiter les méthodes qu'ils peuvent appeler. En utilisant les conventions de nommage comme doubles underscores est censé cacher votre code à partir d'un codeur client occasionnel, mais ne s'arrêtera pas besoin de faire codeurs travail plus sérieux.

Il y a deux réponses selon l'interprétation de la question.

Le premier est en cachant la mise en oeuvre de la méthode de l'interface. Il 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 - si l'on peut encore remplacer accidentellement (ou autre).

La deuxième réponse, en supposant que ce soit sur les performances et inline, est rendu possible, mais en fonction locale C à la place. Si vous voulez une méthode « foo privée (NSString *arg) », vous feriez void MyClass_foo(MyClass *self, NSString *arg) et l'appeler en fonction C comme MyClass_foo(self,arg). La syntaxe est différente, mais il agit avec le genre sain d'esprit des caractéristiques de performance des méthodes privées de C ++.

Bien que cela répond à la question, je tiens à souligner que la catégorie sans nom est de loin le moyen Objective-C plus courante de le faire.

Objective-C ne supporte pas les méthodes privées, car il ne les a pas besoin.

En C ++, chaque méthode doit être visible dans la déclaration de la classe. Vous ne pouvez pas avoir des méthodes que quelqu'un y compris le fichier d'en-tête ne peut pas voir. Donc, si vous voulez des méthodes que le code en dehors de votre mise en œuvre ne doit pas utiliser, vous avez pas le choix, le compilateur vous devez donner un outil pour que vous puissiez lui dire que la méthode ne doit pas être utilisé, c'est le mot-clé « privée ».

Dans Objective-C, vous pouvez avoir des méthodes qui ne sont pas dans le fichier d'en-tête. Ainsi, vous obtenez le même but très facilement ne pas ajouter la méthode dans le 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 tous les utilisateurs d'une classe parce que vous avez changé les méthodes privées.

Pour les variables d'instance, que vous avez utilisé pour déclarer dans le fichier d'en-tête (non plus), @private, @public et @protected sont disponibles.

Une réponse manquante est ici: parce que les méthodes privées sont une mauvaise idée d'un point de vue évolvabilité. Il peut sembler une bonne idée de faire une méthode privée lors de l'écriture, mais il est une forme de liaison anticipée. Le contexte peut changer, et un utilisateur plus tard pourrait vouloir utiliser une implémentation différente. Un peu provocateur: « Les développeurs Agile ne pas utiliser des méthodes privées »

D'une certaine manière, comme Smalltalk, Objective-C est pour les programmeurs adultes. Nous apprécions savoir ce que le développeur d'origine a pris l'interface doit être, et de prendre la responsabilité de faire face aux conséquences si nous devons changer la mise en œuvre. Alors oui, il est philosophie, pas mise en œuvre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top