Wie gebe ich einen Strukturwert aus einer Laufzeit-definierten Klassenmethode unter ARC zurück?

8

Ich habe eine Klassenmethode, die ein CGSize zurückgibt, und ich möchte es über die Objective-C-Laufzeitfunktionen aufrufen, weil mir die Klassen- und Methodennamen als Zeichenfolgenwerte gegeben werden.

Ich kompiliere mit ARC-Flags in XCode 4.2.

Methodensignatur:

%Vor%

Als erstes habe ich versucht, es mit objc_msgSend wie folgt aufzurufen:

%Vor%

Dies ist mit "EXC_BAD_ACCESS" und ohne Stack-Trace abgestürzt. Ich habe das zuerst verwendet, weil die Dokumentation für objc_msgSend sagt,

  

Bei einem Methodenaufruf generiert der Compiler einen Aufruf an eine der Funktionen objc_msgSend , objc_msgSend_stret , objc_msgSendSuper oder objc_msgSendSuper_stret . [...] Methoden, die Datenstrukturen als Rückgabewerte haben, werden mit objc_msgSendSuper_stret und objc_msgSend_stret gesendet.

Als nächstes habe ich objc_msgSend_stret so verwendet:

%Vor%

Die Verwendung der obigen Signatur gibt mir die folgenden zwei Compilerfehler und zwei Warnungen:

  

error: Automatische Referenzzählung Problem: Implizite Konvertierung eines Nicht-Objective-C-Zeigertyps 'CGSize *' (aka 'struct CGSize *') in 'id' ist mit ARC nicht zulässig

     

Warnung: Semantisches Problem: Inkompatible Zeigertypen übergeben 'CGSize *' (aka 'struct CGSize *') an Parameter des Typs 'id'

     

-Fehler: Automatische Referenzzählung Problem: Implizite Konvertierung eines Objective-C-Zeigers in 'SEL' ist mit ARC

nicht erlaubt      

Warnung: Semantisches Problem: Inkompatible Zeigerarten übergeben       '__unsafe_unretted Class' zum Parameter vom Typ 'SEL'

Wenn ich mir die Deklaration der Methode ansehe, ist es:

%Vor%

ist identisch mit objc_msgSend :

%Vor%

Dies erklärt die Compilerfehler für mich, aber was verwende ich auf der Runtime-Ebene, um eine Klasse und ihre statische Methode zur Laufzeit aufzurufen und einen Strukturwert zurückzugeben?

    
Jonas Gardner 06.12.2011, 19:39
quelle

2 Antworten

15

Sie müssen objc_msgSend_stret auf den korrekten Funktionszeigertyp anwenden. Es ist definiert als void objc_msgSend_stret(id, SEL, ...) , was ein unangemessener Typ ist, um tatsächlich anzurufen. Du solltest etwas wie

verwenden %Vor%

Hier werfen wir nur objc_msgSend_stret auf eine Funktion vom Typ (CGSize (*)(id, SEL, NSString*)) , was der tatsächliche Typ von IMP ist, der +contentSize: implementiert.

Beachten Sie, dass wir auch @selector(contentSize:) verwenden, da es keinen Grund gibt, NSSelectorFromString() für zur Kompilierungszeit bekannte Selektoren zu verwenden.

Beachten Sie auch, dass das Umwandeln des Funktionszeigers auch für reguläre Aufrufe von objc_msgSend() erforderlich ist. Selbst wenn objc_msgSend() in Ihrem speziellen Fall direkt aufgerufen wird, wird davon ausgegangen, dass der ABAR-Aufruf der varargs-Methode der gleiche wie der ABI für den Aufruf einer Nicht-Varargsmethode ist, was möglicherweise nicht auf allen Plattformen zutrifft.

>     
Kevin Ballard 06.12.2011, 20:06
quelle
7

Wenn Sie eine Struktur von Ihrer Klassenmethode abrufen möchten, können Sie eine NSInvocation wie folgt verwenden:

%Vor%

Am Ende sollte returnStruct Ihren Strukturwert enthalten. Ich habe das gerade in einer ARC-fähigen Anwendung getestet und das funktioniert gut.

    
Brad Larson 06.12.2011 20:08
quelle