Kann ich einen Ziel-C-Selektor in eine Struktur einfügen?

7

Ich wollte eine Reihe von Rechtecken mit entsprechenden Aktionen verknüpfen, also habe ich es versucht

%Vor%

aber ich bekomme den Fehler "Initialisierungselement ist nicht konstant". Gibt es einen Grund dafür, dass das, was ich versuche zu tun, generell nicht erlaubt ist oder im globalen Rahmen nicht erlaubt ist, oder habe ich einen kleinen Satzfehler?

    
David Maymudes 11.09.2009, 22:02
quelle

3 Antworten

23

Diese Antwort gibt an, warum "initializer element is not constant" .

Gegeben das folgende Beispiel:

%Vor%

Kompiliert zu so etwas für die i386 -Architektur:

%Vor%

Dieser Teil definiert zwei lokale (in Bezug auf den Assembly-Code) "Variablen" (tatsächlich Labels), L_OBJC_METH_VAR_NAME_4 und L_OBJC_SELECTOR_REFERENCES_5 . Der Text .objc_meth_var_names und .objc_message_refs , kurz vor den Variablenvariablen, teilt dem Assembler mit, in welchen Abschnitt der Objektdatei "das Folgende" eingefügt werden soll. Die Abschnitte sind für den Linker sinnvoll. L_OBJC_SELECTOR_REFERENCES_5 wird anfänglich auf die Adresse von L_OBJC_METH_VAR_NAME_4 gesetzt.

Zum Ausführungsladezeitpunkt, bevor das Programm ausgeführt wird, führt der Linker etwas wie folgt aus:

  • Iteriert jeden Eintrag in .objc_message_refs Abschnitt.
  • Jeder Eintrag wird anfänglich auf einen Zeiger auf 0 terminated C string.
  • gesetzt
  • In unserem Beispiel wird der Zeiger anfänglich auf den Wert gesetzt Adresse von L_OBJC_METH_VAR_NAME_4 , die enthält die Zeichenfolge ASCII C "constantSelector:test:" .
  • Es führt dann aus %Code% und speichert den zurückgegebenen Wert um %Code%. Der Linker, welche private Implementierungsdetails kennt, darf sel_registerName("constantSelector:test:") nicht wörtlich heißen.

Im Wesentlichen führt der Linker dies zur Ladezeit für unser Beispiel aus:

%Vor%

Deshalb muss das L_OBJC_SELECTOR_REFERENCES_5 - das Initialisierungselement zur Kompilierungszeit konstant sein. Der Wert ist erst bekannt, wenn das Programm ausgeführt wird. Auch dann werden Ihre sel_registerName() -Deklarationen in einem anderen Linker-Abschnitt gespeichert, dem "initializer element is not constant" -Abschnitt. Der Linker weiß nur, wie er struct -Werte im Abschnitt .data aktualisiert, und es gibt keine Möglichkeit, den berechneten SEL -Wert von .objc_message_refs an eine beliebige Stelle in SEL .

Der .objc_message_refs Quellcode ...

%Vor%

... wird zu:

%Vor%

Da der Linker seine gesamte Arbeit vor der Ausführung des Programms erledigt, enthält .data den genau gleichen Wert, den Sie erhalten würden, wenn Sie C :

aufrufen würden %Vor%

Der Unterschied besteht darin, dass es sich um einen Funktionsaufruf handelt. Die Funktion muss die eigentliche Arbeit zum Auffinden des Selektors ausführen, wenn sie bereits registriert wurde, oder sie muss einen neuen L_OBJC_SELECTOR_REFERENCES_5 Wert zuweisen, um den Selektor zu registrieren. Dies ist wesentlich langsamer als das Laden eines konstanten Wertes. Obwohl dies "langsamer" ist, können Sie eine beliebige sel_registerName("constantSelector:test:") -Zeichenfolge übergeben. Dies kann nützlich sein, wenn:

  • Der Selektor ist zur Kompilierzeit nicht bekannt.
  • Der Selektor ist erst kurz vor dem Aufruf von SEL bekannt.
  • Sie müssen den Selektor zur Laufzeit dynamisch variieren.

Alle Selektoren müssen C durchlaufen, wodurch jedes sel_registerName() genau einmal registriert wird. Dies hat den Vorteil, dass für jeden gegebenen Selektor überall genau ein Wert vorhanden ist. Obwohl ein privates Detail der Implementierung, ist sel_registerName() "normalerweise" nur ein SEL -Zeiger auf eine Kopie der Selektoren SEL string text.

Jetzt weißt du es. Und Wissen ist die halbe Miete!

    
johne 12.09.2009, 03:27
quelle
4

Wie wäre es mit:

%Vor%

Registrieren Sie zur Laufzeit die Selektoren:

%Vor%

Ausgabe:

%Vor%

Weitere Informationen zu sel_registerName() finden Sie unter Objective-C 2.0-Laufzeitreferenz .

    
Alex Reynolds 11.09.2009 23:18
quelle
-1

Sieht aus, als erfindest du NSCell hier neu. Wenn Sie ein Menü implementieren möchten, warum verwenden Sie keine vorhandenen UI-Klassen?

    
NSResponder 12.09.2009 14:57
quelle

Tags und Links