-forwardInvocation arbeitet mit Clang - LLVM aber nicht mit GCC
-
12-09-2019 - |
Frage
Der folgende Code implementiert eine NSProxy Unterklasse, die Methoden zu einer NSNumber Instanz weiterleitet.
Doch beim Aufruf [nsproxy floatvalue] Ich erhalte 0.0 unter GCC 4.2.
Unter LLVM-Clang erhalte ich die richtige Antwort 42.0.
Jede Idee, was ist hier los?
(übrigens diese unter Garbage Collection ausgeführt wird)
-(id) init;
{
_result = [NSNumber numberWithFloat:42.0];
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [[_result class] instanceMethodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation setTarget:_result];
[anInvocation invoke];
return;
}
Lösung
Ihre Proxy-Klasse deklariert die Nachricht nicht Signatur für -floatValue
. Da es eine Fließkommazahl zurückgibt, kann das ein Problem sein. Weil Sie nicht erklärt haben, an jeden Ort und vermutlich es wirft nicht Ihr Proxy-Objekt in seine dargestellt Klasse hat der Compiler bei der Methodensignatur zu erraten. In diesem Fall schätzt die GCC-Compiler, dass die Nachricht einen id
Zeiger zurück.
In Objective-C, abhängig von der Signatur der Nachricht und der Architektur der Maschine erhalten verschiedene Funktionen für die Verarbeitung der Nachricht und ihre Rückgabewerte verwendet. Auf x86-Rechner Nachrichten, die einen Fließkommawert zurückgeben, werden durch objc_msgSend_fpret
während Funktionen aufgerufen, die void
und id
Verwendung objc_msgSend
zurück.
Da die GCC-Compiler davon aus, dass der Rückgabewert ist ein id
es die letztere Funktion verwendet und verarbeitet falsch das Ergebnis. Das Clang der Lage ist, diese richtig zu handhaben ist interessant, aber ich würde auf diesem Verhalten verlassen zögern. Es wäre besser, eine Kategorie auf Ihrem Proxy für alle Methoden zu erklären, dass Sie die Weiterleitung sein werden. Das hat auch den Vorteil, die Warnung zu entfernen, die für die Codezeile erzeugt wurde die floatValue
Methode aufrufen.
@interface Foo (ProxyMethods)
- (float)floatValue;
@end
Andere Tipps
Jede init
Methode sollte [super init];
rufen unerwartetes Verhalten zu verhindern. Wie so:
- (id)init {
self = [super init];
if (self) {
// Your init code
}
return self;
}