Ich bin noch ein bisschen neu in Objective-C und frage mich, was der Unterschied zwischen den folgenden beiden Aussagen ist.
[object performSelector:@selector(doSomething)];
[object doSomething];
Ich bin noch ein bisschen neu in Objective-C und frage mich, was der Unterschied zwischen den folgenden beiden Aussagen ist.
[object performSelector:@selector(doSomething)];
[object doSomething];
Antworten:
Grundsätzlich können Sie mit performSelector dynamisch bestimmen, welcher Selektor einen Selektor für das angegebene Objekt aufrufen soll. Mit anderen Worten, der Selektor muss nicht vor der Laufzeit festgelegt werden.
Also, obwohl diese gleichwertig sind:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
Mit dem zweiten Formular können Sie Folgendes tun:
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
bevor Sie die Nachricht senden.
performSelector:
ist etwas, das Sie wahrscheinlich nur tun, wenn Sie eine Zielaktion in Ihrer Klasse implementieren. Die Geschwister performSelectorInBackground:withObject:
und performSelectorOnMainThread:withObject:waitUntilDone:
sind oft nützlicher. Zum Laichen eines Hintergrundthreads und zum Zurückrufen von Ergebnissen aus diesem Hintergrundthread an den Hauptthread.
performSelector
ist auch nützlich, um Kompilierungswarnungen zu unterdrücken. Wenn Sie wissen, dass die Methode vorhanden ist (wie nach der Verwendung respondsToSelector
), wird Xcode daran gehindert, "möglicherweise nicht zu antworten your_selector
" zu sagen . Verwenden Sie es einfach nicht, anstatt die wahre Ursache der Warnung herauszufinden. ;)
Für dieses sehr grundlegende Beispiel in der Frage,
[object doSomething];
[object performSelector:@selector(doSomething)];
Es gibt keinen Unterschied, was passieren wird. doSomething wird vom Objekt synchron ausgeführt. Nur "doSomething" ist eine sehr einfache Methode, die nichts zurückgibt und keine Parameter benötigt.
Wäre es etwas komplizierter, wie:
(void)doSomethingWithMyAge:(NSUInteger)age;
Dinge würden kompliziert werden, weil [object doSomethingWithMyAge: 42];
kann mit keiner Variante von "performSelector" mehr aufgerufen werden, da alle Varianten mit Parametern nur Objektparameter akzeptieren.
Der Selektor hier wäre "doSomethingWithMyAge:", aber jeder Versuch dazu
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
wird einfach nicht kompiliert. Das Übergeben einer NSNumber: @ (42) anstelle von 42 würde ebenfalls nicht helfen, da die Methode einen grundlegenden C-Typ erwartet - kein Objekt.
Darüber hinaus gibt es performSelector-Varianten mit bis zu 2 Parametern, nicht mehr. Während Methoden oft viel mehr Parameter haben.
Ich habe herausgefunden, dass obwohl synchrone Varianten von performSelector:
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
Immer ein Objekt zurückgeben, ich konnte auch ein einfaches BOOL oder NSUInteger zurückgeben, und es hat funktioniert.
Eine der beiden Hauptanwendungen von performSelector besteht darin, den Namen der Methode, die Sie ausführen möchten, dynamisch zusammenzustellen, wie in einer vorherigen Antwort erläutert. Beispielsweise
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
Die andere Verwendung besteht darin, eine Nachricht asynchron an ein Objekt zu senden, das später im aktuellen Runloop ausgeführt wird. Hierfür gibt es mehrere andere performSelector-Varianten.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
(Ja, ich habe sie aus verschiedenen Foundation-Klassenkategorien wie NSThread, NSRunLoop und NSObject gesammelt.)
Jede der Varianten hat ihr eigenes spezielles Verhalten, aber alle haben etwas gemeinsam (zumindest wenn waitUntilDone auf NO gesetzt ist). Der Aufruf "performSelector" würde sofort zurückkehren und die Nachricht an das Objekt wird erst nach einiger Zeit in den aktuellen Runloop gestellt.
Aufgrund der verzögerten Ausführung ist natürlich kein Rückgabewert für die Methode des Selektors verfügbar, daher der Rückgabewert - (void) in all diesen asynchronen Varianten.
Ich hoffe ich habe das irgendwie abgedeckt ...
@ennuikiller ist genau richtig. Grundsätzlich sind dynamisch generierte Selektoren nützlich, wenn Sie den Namen der Methode, die Sie beim Kompilieren des Codes aufrufen, nicht kennen (und normalerweise auch nicht kennen können).
Ein wesentlicher Unterschied besteht darin, dass -performSelector:
Freunde (einschließlich der Multithread- und verzögerten Varianten ) etwas eingeschränkt sind, da sie für die Verwendung mit Methoden mit 0-2-Parametern ausgelegt sind. Das Aufrufen -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
mit 6 Parametern und das Zurückgeben von NSString
ist beispielsweise ziemlich unhandlich und wird von den bereitgestellten Methoden nicht unterstützt.
NSInvocation
Objekt verwenden.
performSelector:
und Freunde nehmen alle Objektargumente, was bedeutet, dass Sie sie nicht zum Aufrufen verwenden können (zum Beispiel) setAlphaValue:
, da das Argument ein Float ist.
Selektoren sind ein bisschen wie Funktionszeiger in anderen Sprachen. Sie verwenden sie, wenn Sie zur Kompilierungszeit nicht wissen, welche Methode Sie zur Laufzeit aufrufen möchten. Ebenso wie Funktionszeiger kapseln sie nur den Verbteil des Aufrufs. Wenn die Methode Parameter enthält, müssen Sie diese ebenfalls übergeben.
Ein NSInvocation
dient einem ähnlichen Zweck, außer dass es mehr Informationen zusammenhält. Es enthält nicht nur den Verbteil, sondern auch das Zielobjekt und die Parameter. Dies ist nützlich, wenn Sie eine Methode für ein bestimmtes Objekt mit bestimmten Parametern nicht jetzt, sondern in Zukunft aufrufen möchten. Sie können ein geeignetes erstellen NSInvocation
und es später abfeuern.
Es gibt einen weiteren subtilen Unterschied zwischen den beiden.
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
Hier ist der Auszug aus der Apple-Dokumentation
"performSelector: withObject: afterDelay: Führt den angegebenen Selektor für den aktuellen Thread während des nächsten Run-Loop-Zyklus und nach einer optionalen Verzögerungszeit aus. Da er bis zum nächsten Run-Loop-Zyklus wartet, um den Selector auszuführen, bieten diese Methoden eine automatische Mini-Verzögerung von Der aktuell ausgeführte Code. Mehrere Selektoren in der Warteschlange werden nacheinander in der Reihenfolge ausgeführt, in der sie in die Warteschlange gestellt wurden. "
performSelector:withObject:afterDelay:
, aber die Frage und Ihr Snippet verwenden performSelector:
eine völlig andere Methode. Aus den Dokumenten dafür: <quote> Die performSelector:
Methode entspricht dem Senden einer aSelector
Nachricht direkt an den Empfänger. </
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
alle verhalten sich gleich, was ein Fehler war.