Mit dieser NSObject
Methode performSelector:withObject:afterDelay:
kann ich nach einer bestimmten Zeit eine Methode für das Objekt mit einem Objektargument aufrufen. Es kann nicht für Methoden mit einem Nicht-Objekt-Argument verwendet werden (z. B. Ints, Floats, Strukturen, Nicht-Objekt-Zeiger usw.).
Was ist der einfachste Weg, um dasselbe mit einer Methode mit einem Nicht-Objekt-Argument zu erreichen? Ich weiß, dass für reguläre performSelector:withObject:
die Lösung zu verwenden ist NSInvocation
(was übrigens wirklich kompliziert ist). Aber ich weiß nicht, wie ich mit dem Teil "Verzögerung" umgehen soll.
Vielen Dank,
objective-c
cocoa
user102008
quelle
quelle
Antworten:
Folgendes habe ich verwendet, um etwas zu nennen, das ich mit NSInvocation nicht ändern konnte:
quelle
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? Oder meinen Sie, dass sich dieinvoke
Nachricht in der Methode befindet, die Sie nach der Verzögerung ausführen?Wickeln Sie einfach float, boolean, int oder ähnliches in eine NSNumber.
Für Strukturen kenne ich keine praktische Lösung, aber Sie könnten eine separate ObjC-Klasse erstellen, die eine solche Struktur besitzt.
quelle
nil
damit einBOOL
Parameter empfangen wirdNO
(FALSE
)VERWENDEN SIE DIESE ANTWORT NICHT. Ich habe es nur für historische Zwecke verlassen. SIEHE DIE KOMMENTARE UNTEN.
Es gibt einen einfachen Trick, wenn es sich um einen BOOL-Parameter handelt.
Übergeben Sie Null für NEIN und Selbst für JA. nil wird auf den BOOL-Wert NO gesetzt. self wird auf den BOOL-Wert von YES gesetzt.
Dieser Ansatz bricht zusammen, wenn es sich nicht um einen BOOL-Parameter handelt.
Selbst anzunehmen ist ein UIView.
quelle
if ()
testen, aber es ist denkbar, dass einige Codes davon abhängen, dass sie 0 oder 1 sind und somit gewonnen werden Behandeln Sie einen großen Adresswert nicht als gleich 1 (JA).self
mit Adresse wie vor0x0123400
. Mit diesem Ansatz erhalten Sie in 0,4% der Fälle KEIN JA . Worser, mit dieser Wahrscheinlichkeit kann diese Lösung alle Tests bestehen und später enthüllen.Vielleicht NSValue , stellen Sie einfach sicher, dass Ihre Zeiger nach der Verzögerung noch gültig sind (dh keine auf dem Stapel zugewiesenen Objekte).
quelle
NSValue
(wenn möglich) die erwartete "entpacken"type
?Ich weiß, dass dies eine alte Frage ist, aber wenn Sie iOS SDK 4+ erstellen, können Sie Blöcke verwenden, um dies mit sehr geringem Aufwand zu tun und es lesbarer zu machen:
quelle
PerformSelector: WithObject nimmt immer ein Objekt, um Argumente wie int / double / float usw. zu übergeben. Sie können so etwas verwenden.
Genauso können Sie [NSNumber numberWithInt:] etc .... verwenden und bei der Empfangsmethode die Nummer in Ihr Format als [number int] oder [number double] konvertieren.
quelle
Blöcke sind der richtige Weg. Sie können komplexe Parameter haben, Sicherheit eingeben und es ist viel einfacher und sicherer als die meisten alten Antworten hier. Zum Beispiel könnten Sie einfach schreiben:
Mit Blöcken können Sie beliebige Parameterlisten, Referenzobjekte und Variablen erfassen.
Backing-Implementierung (grundlegend):
Beispiel:
Siehe auch Michaels Antwort (+1) für ein anderes Beispiel.
quelle
Ich würde immer empfehlen, dass Sie NSMutableArray als Weitergabeobjekt verwenden. Dies liegt daran, dass Sie dann mehrere Objekte übergeben können, z. B. die gedrückte Taste und andere Werte. NSNumber, NSInteger und NSString sind nur Container mit einem gewissen Wert. Stellen Sie sicher, dass Sie beim Abrufen des Objekts aus dem Array auf einen korrekten Containertyp verweisen. Sie müssen NS-Container weitergeben. Dort können Sie den Wert testen. Denken Sie daran, dass Container beim Vergleich von Werten isEqual verwenden.
quelle
Ich wollte dies auch tun, aber mit einer Methode, die einen BOOL-Parameter empfängt. Umschließen des Bool-Werts mit NSNumber, Fehler beim Übergeben des Werts. Ich habe keine Idee warum.
Also habe ich einen einfachen Hack gemacht. Ich füge den erforderlichen Parameter in eine andere Dummy-Funktion ein und rufe diese Funktion mit dem performSelector auf, wobei withObject = nil;
quelle
-performSelector[...]
Methode ein Objekt erwartet (anstelle eines primitiven Datentyps) und nicht weiß, dass der aufgerufene Selektor einen Booleschen Wert akzeptiert, wird die Adresse (Zeigerwert) derNSNumber
Instanz möglicherweise blind inBOOL
(= umgewandelt ungleich Null, dhTRUE
). Vielleicht könnte die Laufzeit schlauer sein als diese und einen Null-Booleschen Wert erkennen, der in einNSNumber
!Ich finde, dass der schnellste (aber etwas schmutzige) Weg, dies zu tun, darin besteht, objc_msgSend direkt aufzurufen. Es ist jedoch gefährlich, es direkt aufzurufen, da Sie die Dokumentation lesen und sicherstellen müssen, dass Sie die richtige Variante für den Typ des Rückgabewerts verwenden, und weil objc_msgSend aus Gründen des Compiler-Komforts als vararg definiert ist, aber tatsächlich als schneller Montagekleber implementiert ist . Hier ist ein Code zum Aufrufen einer Delegate-Methode - [delegate integerDidChange:], die ein einzelnes Integer-Argument akzeptiert.
Dadurch wird zuerst der Selektor gespeichert, da wir mehrmals darauf verweisen werden und es einfach wäre, einen Tippfehler zu erstellen. Anschließend wird überprüft, ob der Delegat tatsächlich auf den Selektor reagiert. Dies kann ein optionales Protokoll sein. Anschließend wird ein Funktionszeigertyp erstellt, der die tatsächliche Signatur des Selektors angibt. Beachten Sie, dass alle Objective-C-Nachrichten zwei versteckte erste Argumente haben, nämlich das zu sendende Objekt und die gesendete Auswahl. Dann erstellen wir einen Funktionszeiger des entsprechenden Typs und setzen ihn so, dass er auf die zugrunde liegende Funktion objc_msgSend zeigt. Beachten Sie, dass Sie eine andere Variante von objc_msgSend verwenden müssen, wenn der Rückgabewert ein float oder eine Struktur ist. Senden Sie die Nachricht abschließend mit derselben Maschine, die Objective-C unter den Arbeitsblättern verwendet.
quelle
Sie können einfach NSTimer verwenden, um einen Selektor aufzurufen:
quelle
yourMethod:
in Ihrem Beispiel ist der Timer selbst, für den Sie nichts übergeben habenuserInfo
. Selbst wenn Sie verwendet hättenuserInfo
, müssten Sie den Wert immer noch einpacken, wie es der Schaden und Remus Rusanu vorschlugen.Das Aufrufen von performSelector mit einer NSNumber oder einem anderen NSValue funktioniert nicht. Anstatt den Wert von NSValue / NSNumber zu verwenden, wird der Zeiger effektiv auf ein int, float oder was auch immer umgewandelt und verwendet.
Die Lösung ist jedoch einfach und offensichtlich. Erstellen Sie die NSInvocation und rufen Sie an
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
quelle
Pehaps ... ok, sehr wahrscheinlich fehlt mir etwas, aber warum nicht einfach einen Objekttyp, z. B. NSNumber, als Container für Ihre Nicht-Objekttyp-Variable wie CGFloat erstellen?
quelle