Ich habe in Objective-C eine Reihe von Strategien zur Deklaration halbprivater Methoden gesehen , aber es scheint keinen Weg zu geben, eine wirklich private Methode zu erstellen. Ich akzeptiere das. Aber warum ist das so? Jede Erklärung, die ich im Wesentlichen gesagt habe: "Sie können es nicht tun, aber hier ist eine enge Annäherung."
Es gibt eine Reihe von Schlüsselwörtern angewendet ivars
(Mitglieder) , die ihren Umfang zu steuern, zum Beispiel @private
, @public
, @protected
. Warum kann dies nicht auch für Methoden durchgeführt werden? Es scheint etwas zu sein, das die Laufzeit unterstützen sollte. Gibt es eine zugrunde liegende Philosophie, die mir fehlt? Ist das absichtlich?
objective-c
objective-c-runtime
Rob Jones
quelle
quelle
Antworten:
Die Antwort ist ... na ja ... einfach. Einfachheit und Konsistenz in der Tat.
Objective-C ist zum Zeitpunkt des Versands der Methode rein dynamisch. Insbesondere durchläuft jeder Methodenversand genau den gleichen dynamischen Methodenauflösungspunkt wie jeder andere Methodenversand. Zur Laufzeit hat jede Methodenimplementierung genau die gleiche Exposition und alle von der Objective-C-Laufzeit bereitgestellten APIs, die mit Methoden und Selektoren arbeiten, funktionieren für alle Methoden gleich.
Wie viele (sowohl hier als auch in anderen Fragen) geantwortet haben, werden private Methoden zur Kompilierungszeit unterstützt. Wenn eine Klasse keine Methode in ihrer öffentlich verfügbaren Schnittstelle deklariert, ist diese Methode für Ihren Code möglicherweise nicht vorhanden. Mit anderen Worten, Sie können alle verschiedenen Kombinationen der Sichtbarkeit erzielen, die zur Kompilierungszeit gewünscht werden, indem Sie Ihr Projekt entsprechend organisieren.
Das Duplizieren derselben Funktionalität in die Laufzeit hat wenig Vorteile. Es würde eine enorme Menge an Komplexität und Overhead hinzufügen. Und selbst bei all dieser Komplexität würde es nicht alle außer den gelegentlichsten Entwicklern daran hindern, Ihre angeblich "privaten" Methoden auszuführen.
Dies würde jedoch die reine Dynamik der Sprache untergraben. Nicht mehr würde jeder Methodenversand einen identischen Versandmechanismus durchlaufen. Stattdessen würden Sie in einer Situation zurückbleiben, in der sich die meisten Methoden in eine Richtung verhalten und eine kleine Handvoll nur anders sind.
Dies geht über die Laufzeit hinaus, da es in Cocoa viele Mechanismen gibt, die auf der konsistenten Dynamik von Objective-C aufbauen. Beispielsweise müssten sowohl die Schlüsselwertcodierung als auch die Schlüsselwertbeobachtung entweder stark modifiziert werden, um private Methoden zu unterstützen - höchstwahrscheinlich durch Schaffung einer ausnutzbaren Lücke - oder private Methoden wären nicht kompatibel.
quelle
Die Laufzeit könnte es unterstützen, aber die Kosten wären enorm. Jeder gesendete Selektor müsste überprüft werden, ob er für diese Klasse privat oder öffentlich ist, oder jede Klasse müsste zwei separate Versandtabellen verwalten. Dies gilt beispielsweise nicht für Variablen, da diese Schutzstufe zur Kompilierungszeit ausgeführt wird.
Außerdem müsste die Laufzeit überprüfen, ob der Absender einer privaten Nachricht zur selben Klasse gehört wie der Empfänger. Sie können auch private Methoden umgehen. Wenn die Klasse verwendet wird
instanceMethodForSelector:
, kann sie die RückgabeIMP
an eine andere Klasse weitergeben, damit diese die private Methode direkt aufrufen kann.Private Methoden konnten den Nachrichtenversand nicht umgehen. Stellen Sie sich das folgende Szenario vor:
Eine Klasse
AllPublic
verfügt über eine öffentliche InstanzmethodedoSomething
Eine andere Klasse
HasPrivate
hat eine private Instanzmethode, die auch aufgerufen wirddoSomething
Sie erstellen ein Array, das eine beliebige Anzahl von Instanzen von
AllPublic
und enthältHasPrivate
Sie haben die folgende Schleife:
Wenn Sie diese Schleife von innen
AllPublic
ausführen würden, müsste die Laufzeit das SendendoSomething
derHasPrivate
Instanzen stoppen. Diese Schleife wäre jedoch verwendbar, wenn sie sich innerhalb derHasPrivate
Klasse befindet.quelle
Die bisher veröffentlichten Antworten beantworten die Frage aus philosophischer Sicht gut, daher werde ich einen pragmatischeren Grund nennen: Was würde durch eine Änderung der Semantik der Sprache erreicht werden? Es ist einfach genug, private Methoden effektiv zu "verstecken". Stellen Sie sich beispielsweise vor, Sie haben eine Klasse in einer Header-Datei deklariert, wie folgt:
Wenn Sie "private" Methoden benötigen, können Sie diese auch in die Implementierungsdatei einfügen:
Sicher, es ist nicht ganz dasselbe wie private C ++ / Java-Methoden, aber es ist effektiv nah genug. Warum also die Semantik der Sprache sowie den Compiler, die Laufzeit usw. ändern, um eine Funktion hinzuzufügen, die bereits in einer akzeptablen Form emuliert ist? Weg? Wie in anderen Antworten erwähnt, würde die Semantik der Nachrichtenübermittlung - und ihre Abhängigkeit von der Laufzeitreflexion - den Umgang mit "privaten" Nachrichten nicht trivial machen.
quelle
Die einfachste Lösung besteht darin, einige statische C-Funktionen in Ihren Objective-C-Klassen zu deklarieren. Diese haben nur den Dateibereich gemäß den C-Regeln für das statische Schlüsselwort und können daher nur von Methoden in dieser Klasse verwendet werden.
Überhaupt keine Aufregung.
quelle
Ja, dies kann ohne Beeinträchtigung der Laufzeit erfolgen, indem eine Technik verwendet wird, die bereits von den Compilern für die Behandlung von C ++ verwendet wird: Namensveränderung.
Es wurde nicht getan, weil nicht festgestellt wurde, dass es einige erhebliche Schwierigkeiten im Codierungsproblemraum lösen würde, die andere Techniken (z. B. Präfixieren oder Unterstreichen) ausreichend umgehen können. IOW, du brauchst mehr Schmerz, um tief verwurzelte Gewohnheiten zu überwinden.
Sie können Patches zu clang oder gcc hinzufügen, die der Syntax private Methoden hinzufügen und verstümmelte Namen generieren, die sie allein beim Kompilieren erkannt (und sofort vergessen) haben. Dann könnten andere Mitglieder der Objective-C-Community feststellen, ob es sich tatsächlich lohnt oder nicht. Auf diese Weise ist es wahrscheinlich schneller als der Versuch, die Entwickler zu überzeugen.
quelle
Im Wesentlichen hat dies mit der Nachrichtenübermittlungsform von Objective-C für Methodenaufrufe zu tun. Jede Nachricht kann an jedes Objekt gesendet werden, und das Objekt wählt aus, wie auf die Nachricht reagiert werden soll. Normalerweise wird die nach der Nachricht benannte Methode ausgeführt, es kann jedoch auch auf andere Weise reagiert werden. Dies macht private Methoden nicht völlig unmöglich - Ruby macht es mit einem ähnlichen Nachrichtenübermittlungssystem - aber es macht sie etwas umständlich.
Sogar Rubys Implementierung privater Methoden ist für die Leute aufgrund der Seltsamkeit etwas verwirrend (Sie können dem Objekt jede Nachricht senden, die Sie mögen, außer den auf dieser Liste !). Im Wesentlichen funktioniert Ruby so, dass private Methoden nicht mit einem expliziten Empfänger aufgerufen werden dürfen. In Objective-C würde es noch mehr Arbeit erfordern, da Objective-C diese Option nicht hat.
quelle
Dies ist ein Problem mit der Laufzeitumgebung von Objective-C. Während C / C ++ in unlesbaren Maschinencode kompiliert wird, behält Objective-C einige für Menschen lesbare Attribute wie Methodennamen als Zeichenfolgen bei . Dies gibt Objective-C die Möglichkeit, reflektierende Merkmale auszuführen .
BEARBEITEN: Eine reflektierende Sprache ohne strenge private Methoden zu sein, macht Objective-C "pythonischer", da Sie anderen Personen vertrauen, die Ihren Code verwenden, anstatt einzuschränken, welche Methoden sie aufrufen können. Die Verwendung von Namenskonventionen wie doppelte Unterstriche soll Ihren Code vor einem gelegentlichen Client-Codierer verbergen, verhindert jedoch nicht, dass Codierer ernsthaftere Arbeiten ausführen müssen.
quelle
Abhängig von der Interpretation der Frage gibt es zwei Antworten.
Die erste besteht darin, die Methodenimplementierung vor der Schnittstelle zu verbergen. Dies wird normalerweise bei einer Kategorie ohne Namen verwendet (z
@interface Foo()
. B. ). Dadurch kann das Objekt diese Nachrichten senden, andere jedoch nicht - obwohl dies möglicherweise versehentlich (oder auf andere Weise) überschrieben wird.Die zweite Antwort unter der Annahme, dass es sich um Leistung und Inlining handelt, wird ermöglicht, jedoch als lokale C-Funktion. Wenn Sie eine 'private foo (
NSString *arg
)' - Methode wünschen , würden Sievoid MyClass_foo(MyClass *self, NSString *arg)
sie als C-Funktion wie ausführenMyClass_foo(self,arg)
. Die Syntax ist unterschiedlich, entspricht jedoch den normalen Leistungsmerkmalen der privaten Methoden von C ++.Obwohl dies die Frage beantwortet, sollte ich darauf hinweisen, dass die Kategorie ohne Namen bei weitem die üblichere Objective-C-Methode ist, um dies zu tun.
quelle
Objective-C unterstützt keine privaten Methoden, da diese nicht benötigt werden.
In C ++ muss jede Methode in der Deklaration der Klasse sichtbar sein. Sie können keine Methoden haben, die jemand einschließlich der Header-Datei nicht sehen kann. Wenn Sie also Methoden wünschen, die Code außerhalb Ihrer Implementierung nicht verwenden sollte, haben Sie keine Wahl. Der Compiler muss Ihnen ein Tool zur Verfügung stellen, damit Sie ihm mitteilen können, dass die Methode nicht verwendet werden darf, dh das Schlüsselwort "private".
In Objective-C können Methoden vorhanden sein, die sich nicht in der Header-Datei befinden. Sie erreichen den gleichen Zweck also sehr einfach, indem Sie die Methode nicht zur Header-Datei hinzufügen. Private Methoden sind nicht erforderlich. Objective-C hat auch den Vorteil, dass Sie nicht jeden Benutzer einer Klasse neu kompilieren müssen, da Sie private Methoden geändert haben.
Beispielsweise sind Variablen verfügbar, die Sie früher in der Header-Datei deklarieren mussten (nicht mehr), @private, @public und @protected.
quelle
Eine fehlende Antwort lautet hier: Weil private Methoden aus Sicht der Evolvabilität eine schlechte Idee sind. Es mag eine gute Idee sein, eine Methode beim Schreiben privat zu machen, aber es ist eine Form der frühen Bindung. Der Kontext kann sich ändern, und ein späterer Benutzer möchte möglicherweise eine andere Implementierung verwenden. Ein bisschen provokativ: "Agile Entwickler verwenden keine privaten Methoden"
In gewisser Weise ist Objective-C genau wie Smalltalk für erwachsene Programmierer gedacht. Wir legen Wert darauf, zu wissen, wie der ursprüngliche Entwickler die Schnittstelle angenommen hat, und übernehmen die Verantwortung, mit den Konsequenzen umzugehen, wenn wir die Implementierung ändern müssen. Also ja, es ist Philosophie, keine Umsetzung.
quelle