Ich habe gerade angefangen, Objective-C zu programmieren, und mit einem Hintergrund in Java frage ich mich, wie Leute, die Objective-C-Programme schreiben, mit privaten Methoden umgehen.
Ich verstehe, dass es verschiedene Konventionen und Gewohnheiten geben kann, und denke über diese Frage als Aggregator der besten Techniken nach, die Menschen verwenden, um mit privaten Methoden in Objective-C umzugehen.
Bitte geben Sie bei der Veröffentlichung ein Argument für Ihren Ansatz an. Warum ist es gut? Welche Nachteile hat es (die Sie kennen) und wie gehen Sie damit um?
Was meine bisherigen Erkenntnisse betrifft.
Es ist möglich, in der Datei MyClass.m definierte Kategorien [z. B. MyClass (Private)] zu verwenden, um private Methoden zu gruppieren.
Dieser Ansatz hat zwei Probleme:
- Xcode (und Compiler?) Überprüft nicht, ob Sie alle Methoden in der privaten Kategorie im entsprechenden @ Implementierungsblock definieren
- Sie müssen @interface, das Ihre private Kategorie deklariert, am Anfang der Datei MyClass.m einfügen, andernfalls beschwert sich Xcode mit einer Nachricht wie "self antwortet möglicherweise nicht auf die Nachricht" privateFoo ".
Die erste Ausgabe kann mit einer leeren Kategorie [z. B. MyClass ()] umgangen werden.
Der zweite stört mich sehr. Ich würde gerne sehen, dass private Methoden am Ende der Datei implementiert (und definiert) werden. Ich weiß nicht, ob das möglich ist.
quelle
Antworten:
Wie andere bereits gesagt haben, gibt es in Objective-C keine private Methode. Doch in Objective-C beginnen 2.0 (was bedeutet , Mac OS X Leopard, iPhone OS 2.0 und höher) Sie können eine Kategorie mit einem leeren Namen (dh erstellen
@interface MyClass ()
) genannt Klassenerweiterung . Das Besondere an einer Klassenerweiterung ist, dass die Methodenimplementierungen@implementation MyClass
mit den öffentlichen Methoden identisch sein müssen . Also strukturiere ich meine Klassen so:In der .h-Datei:
Und in der .m-Datei:
Ich denke, der größte Vorteil dieses Ansatzes besteht darin, dass Sie Ihre Methodenimplementierungen nach Funktionalität gruppieren können, nicht nach der (manchmal willkürlichen) öffentlichen / privaten Unterscheidung.
quelle
if (bSizeDifference && [self isSizeDifferenceSignificant:fWidthCombined])...
Dann kam fWidthCombined immer als 0 durch.Es gibt in Objective-C keine "private Methode", wenn die Laufzeit herausfinden kann, welche Implementierung sie verwenden soll. Das heißt aber nicht, dass es keine Methoden gibt, die nicht Teil der dokumentierten Schnittstelle sind. Für diese Methoden denke ich, dass eine Kategorie in Ordnung ist. Anstatt das
@interface
wie in Punkt 2 oben in die .m-Datei einzufügen, würde ich es in eine eigene .h-Datei einfügen. Eine Konvention folge ich (und habe an anderer Stelle gesehen, ich glaube , es ist ein Apple - Konvention als Xcode jetzt automatische Unterstützung für sie gibt) ist eine solche Datei nach seiner Klasse und Kategorie mit einem + zu nennen , sie zu trennen, so@interface GLObject (PrivateMethods)
finden Sie inGLObject+PrivateMethods.h
. Der Grund für die Bereitstellung der Header-Datei ist, dass Sie sie in Ihre Unit-Test-Klassen importieren können :-).Übrigens, was das Implementieren / Definieren von Methoden am Ende der .m-Datei betrifft, können Sie dies mit einer Kategorie tun, indem Sie die Kategorie am Ende der .m-Datei implementieren:
oder mit einer Klassenerweiterung (die Sache, die Sie als "leere Kategorie" bezeichnen), definieren Sie diese Methoden einfach zuletzt. Objective-C-Methoden können in der Implementierung in beliebiger Reihenfolge definiert und verwendet werden. Es hindert Sie also nichts daran, die "privaten" Methoden am Ende der Datei zu platzieren.
Selbst bei Klassenerweiterungen erstelle ich häufig einen separaten Header (
GLObject+Extension.h
), damit ich diese Methoden bei Bedarf verwenden kann, um die Sichtbarkeit von "Freunden" oder "Geschützten" nachzuahmen.Da diese Antwort ursprünglich geschrieben wurde, hat der Clang-Compiler begonnen, zwei Durchgänge für Objective-C-Methoden durchzuführen. Dies bedeutet, dass Sie vermeiden können, Ihre "privaten" Methoden vollständig zu deklarieren, und ob sie sich über oder unter der aufrufenden Site befinden, werden vom Compiler gefunden.
quelle
Obwohl ich kein Objective-C-Experte bin, definiere ich persönlich nur die Methode bei der Implementierung meiner Klasse. Zugegeben, es muss vor (oben) den Methoden definiert werden, die es aufrufen, aber es erfordert definitiv den geringsten Arbeitsaufwand.
quelle
Das Definieren Ihrer privaten Methoden im
@implementation
Block ist für die meisten Zwecke ideal. Clang sieht diese innerhalb der@implementation
, unabhängig von der Reihenfolge der Deklaration. Es ist nicht erforderlich, sie in einer Klassenfortsetzung (auch als Klassenerweiterung bezeichnet) oder einer benannten Kategorie zu deklarieren.In einigen Fällen müssen Sie die Methode in der Klassenfortsetzung deklarieren (z. B. wenn Sie den Selektor zwischen der Klassenfortsetzung und der verwenden
@implementation
).static
Funktionen sind sehr gut für besonders empfindliche oder geschwindigkeitskritische private Methoden.Eine Konvention zum Benennen von Präfixen kann Ihnen dabei helfen, ein versehentliches Überschreiben privater Methoden zu vermeiden (ich finde den Klassennamen als Präfix sicher).
Benannte Kategorien (z. B.
@interface MONObject (PrivateStuff)
) sind wegen möglicher Namenskollisionen beim Laden keine besonders gute Idee. Sie sind wirklich nur für Freunde oder geschützte Methoden nützlich (die sehr selten eine gute Wahl sind). Um sicherzustellen, dass Sie vor unvollständigen Kategorieimplementierungen gewarnt werden, sollten Sie diese tatsächlich implementieren:Hier ist ein kleiner kommentierter Spickzettel:
MONObject.h
MONObject.m
Ein weiterer Ansatz, der möglicherweise nicht offensichtlich ist: Ein C ++ - Typ kann sowohl sehr schnell sein als auch ein viel höheres Maß an Kontrolle bieten und gleichzeitig die Anzahl der exportierten und geladenen Objektmethoden minimieren.
quelle
Sie können versuchen, eine statische Funktion unterhalb oder oberhalb Ihrer Implementierung zu definieren, die einen Zeiger auf Ihre Instanz verwendet. Es kann auf jede Ihrer Instanzvariablen zugreifen.
quelle
Sie könnten Blöcke verwenden?
Ich bin mir bewusst, dass dies eine alte Frage ist, aber es ist eine der ersten, die ich gefunden habe, als ich nach einer Antwort auf diese Frage gesucht habe. Ich habe diese Lösung nirgendwo anders gesehen, also lassen Sie mich wissen, ob dies etwas Dummes ist.
quelle
static
). Aber ich habe mit dem Zuweisen von Blöcken zu privaten Ivars (nach der init-Methode) experimentiert - im JavaScript-Stil - was auch den Zugriff auf private Ivars ermöglicht, was mit statischen Funktionen nicht möglich ist. Ich bin mir noch nicht sicher, welches ich bevorzuge.Alle Objekte in Objective C entsprechen dem NSObject-Protokoll, das die performSelector: -Methode enthält. Zuvor suchte ich auch nach einer Möglichkeit, einige "helfer- oder private" Methoden zu erstellen, die ich auf öffentlicher Ebene nicht offenlegen musste. Wenn Sie eine private Methode ohne Overhead erstellen möchten und diese nicht in Ihrer Header-Datei definieren müssen, probieren Sie dies aus ...
Definieren Sie Ihre Methode mit einer ähnlichen Signatur wie im folgenden Code ...
Wenn Sie dann auf die Methode verweisen müssen, rufen Sie sie einfach als Selektor auf ...
Diese Codezeile ruft die von Ihnen erstellte Methode auf und enthält keine nervige Warnung, dass sie nicht in der Header-Datei definiert ist.
quelle
Wenn Sie den
@interface
Block oben vermeiden möchten, können Sie die privaten Deklarationen immer in eine andere DateiMyClassPrivate.h
einfügen, die nicht ideal ist, aber die Implementierung nicht überfüllt.MyClass.h
MyClassPrivate.h
MyClass.m
quelle
Eine weitere Sache, die ich hier nicht gesehen habe - Xcode unterstützt .h-Dateien mit dem Namen "_private". Angenommen, Sie haben eine Klasse MyClass - Sie haben MyClass.m und MyClass.h und jetzt können Sie auch MyClass_private.h haben. Xcode erkennt dies und nimmt es in die Liste der "Gegenstücke" im Assistenten-Editor auf.
quelle
Es gibt keine Möglichkeit, das zweite Problem zu umgehen. So funktioniert der C-Compiler (und damit der Objective-C-Compiler). Wenn Sie den XCode-Editor verwenden, sollte das Funktions-Popup das Navigieren in den
@interface
und@implementation
-Blöcken in der Datei erleichtern .quelle
Es gibt einen Vorteil der Abwesenheit privater Methoden. Sie können die Logik, die Sie ausblenden möchten, in die separate Klasse verschieben und als Delegat verwenden. In diesem Fall können Sie das delegierte Objekt als privat markieren und es ist von außen nicht sichtbar. Wenn Sie die Logik in die separate Klasse (möglicherweise mehrere) verschieben, können Sie Ihr Projekt besser gestalten. Weil Ihre Klassen einfacher werden und Ihre Methoden in Klassen mit Eigennamen gruppiert sind.
quelle
Wie andere Leute sagten, ist das Definieren privater Methoden im
@implementation
Block für die meisten Zwecke in Ordnung.Zum Thema Code-Organisation - Ich halte sie gerne zusammen, um die
pragma mark private
Navigation in Xcode zu vereinfachenquelle