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:
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
oderobjc_msgSendSuper_stret
. [...] Methoden, die Datenstrukturen als Rückgabewerte haben, werden mitobjc_msgSendSuper_stret
undobjc_msgSend_stret
gesendet.
Als nächstes habe ich objc_msgSend_stret
so verwendet:
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 erlaubtWarnung: 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
:
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?
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
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.
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.
Tags und Links objective-c struct automatic-ref-counting objective-c-runtime class-method