Ich versuche , eine zu schaffen , NSTimer
in Swift
aber ich einige Probleme haben.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
ist eine Funktion in derselben Klasse.
Ich erhalte eine Fehlermeldung im Editor:
Es wurde keine Überladung für 'init' gefunden, die die angegebenen Argumente akzeptiert
Wenn ich selector: test()
zum selector: nil
Fehler wechsle , verschwindet er.
Ich habe es versucht:
selector: test()
selector: test
selector: Selector(test())
Aber nichts funktioniert und ich kann in den Referenzen keine Lösung finden.
selector: test()
würdetest
den Rückgabewert aufrufen und an dasselector
Argument übergeben.Antworten:
Swift selbst verwendet keine Selektoren - mehrere Entwurfsmuster, die in Objective-C Selektoren verwenden, funktionieren in Swift unterschiedlich. (Verwenden Sie beispielsweise die optionale Verkettung für Protokolltypen oder
is
/as
-tests anstelle vonrespondsToSelector:
und verwenden Sie Verschlüsse, wo immer Sie können, anstattperformSelector:
für eine bessere Typ- / Speichersicherheit.)Es gibt jedoch noch eine Reihe wichtiger ObjC-basierter APIs, die Selektoren verwenden, einschließlich Timer und des Ziel- / Aktionsmusters. Swift bietet den
Selector
Typ für die Arbeit mit diesen. (Swift verwendet dies automatisch anstelle desSEL
Typs von ObjC .)In Swift 2.2 (Xcode 7.3) und höher (einschließlich Swift 3 / Xcode 8 und Swift 4 / Xcode 9):
Selector
Mit dem#selector
Ausdruck können Sie einen aus einem Swift-Funktionstyp erstellen.Das Tolle an diesem Ansatz? Eine Funktionsreferenz wird vom Swift-Compiler überprüft, sodass Sie den
#selector
Ausdruck nur mit tatsächlich vorhandenen Klassen- / Methodenpaaren verwenden können, die als Selektoren verwendet werden können (siehe "Verfügbarkeit der Selektoren" weiter unten). Sie können Ihre Funktionsreferenz auch nur so spezifisch gestalten, wie Sie es benötigen, gemäß den Swift 2.2+ -Regeln für die Benennung von Funktionstypen .(Dies ist tatsächlich eine Verbesserung gegenüber der
@selector()
Direktive von ObjC , da die-Wundeclared-selector
Überprüfung des Compilers nur überprüft, ob der benannte Selektor vorhanden ist. Die Swift-Funktionsreferenz, die Sie übergeben, um die#selector
Existenz, die Zugehörigkeit zu einer Klasse und die Typensignatur zu überprüfen.)Es gibt einige zusätzliche Einschränkungen für die Funktionsreferenzen, die Sie an den
#selector
Ausdruck übergeben:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
) unterschieden werden. Wenn eine Funktion jedoch keine Parameter hat, besteht die einzige Möglichkeit, sie zu unterscheiden, darin, eineas
Umwandlung mit der Typensignatur der Funktion (z . B.foo as () -> ()
vsfoo(_:)
) zu verwenden.var foo: Int
, können Sie#selector(getter: MyClass.foo)
oder verwenden#selector(setter: MyClass.foo)
.Allgemeine Hinweise:
Fälle, in denen
#selector
dies nicht funktioniert, und Benennung: Manchmal haben Sie keine Funktionsreferenz, mit der Sie einen Selektor erstellen können (z. B. mit Methoden, die dynamisch in der ObjC-Laufzeit registriert sind). In diesem Fall können Sie eineSelector
aus einer Zeichenfolge erstellen: z. B.Selector("dynamicMethod:")
obwohl Sie die Gültigkeitsprüfung des Compilers verlieren. Wenn Sie dies tun, müssen Sie die ObjC-Namensregeln befolgen, einschließlich colons (:
) für jeden Parameter.Selektorverfügbarkeit: Die vom Selektor referenzierte Methode muss der ObjC-Laufzeit ausgesetzt sein. In Swift 4 muss jeder Methode, die ObjC ausgesetzt ist, der Deklaration das
@objc
Attribut vorangestellt werden. (In früheren Versionen haben Sie dieses Attribut in einigen Fällen kostenlos erhalten, aber jetzt müssen Sie es explizit deklarieren.)Denken Sie daran, dass
private
Symbole auch nicht der Laufzeit ausgesetzt sind - Ihre Methode muss mindestensinternal
sichtbar sein.Schlüsselpfade: Diese beziehen sich auf Selektoren, sind aber nicht ganz mit diesen identisch. Auch für diese gibt es in Swift 3 eine spezielle Syntax: z
chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Siehe SE-0062 für Details. Und noch mehrKeyPath
Dinge in Swift 4 , stellen Sie also sicher, dass Sie die richtige KeyPath-basierte API anstelle von Selektoren verwenden, falls zutreffend.Weitere Informationen zu Selektoren finden Sie unter Interaktion mit Objective-C-APIs unter Verwenden von Swift mit Cocoa und Objective-C .
Hinweis: Vor Swift 2.2
Selector
konformStringLiteralConvertible
, sodass Sie möglicherweise alten Code finden, in dem bloße Zeichenfolgen an APIs übergeben werden, die Selektoren verwenden. Sie sollten "In aktuelle Swift-Syntax konvertieren" in Xcode ausführen, um diese zu verwenden#selector
.quelle
size:andShape:
benötigen Sie bei einem Namen des ersten Arguments möglicherweise einWith
, dhinitWithData:
fürfunc init(Data data: NSData)
Hier ist ein kurzes Beispiel für die Verwendung der
Selector
Klasse in Swift:Beachten Sie, dass die als Zeichenfolge übergebene Methode zur Laufzeit fehlschlägt, nicht zur Kompilierungszeit und Ihre App zum Absturz bringt. Achtung
quelle
@selector
ist praktisch, aber es wird nicht so formal durchgesetzt, wie Sie vielleicht denken. "Nicht deklarierter Selektor" ist lediglich eine Warnung des Compilers, da zur Laufzeit immer neue Selektoren eingeführt werden können. Überprüfbare / überarbeitbare Selektorreferenzen in Swift wären jedoch eine gute Anforderung für Funktionen .Wenn Ihre (Swift-) Klasse nicht von einer Objective-C-Klasse abstammt, müssen Sie am Ende der Zeichenfolge für den Zielmethodennamen einen Doppelpunkt haben und die Eigenschaft @objc mit Ihrer Zielmethode verwenden, z
Andernfalls wird zur Laufzeit der Fehler "Nicht erkannter Selektor" angezeigt.
quelle
Selector
Schlüsselwort ist nicht obligatorisch. In diesem Fall muss die Unterschrift also@objc func method(timer: NSTimer) {/*code*/}
@objc
arbeitete für mich. Ich musste nichttimer: NSTimer
in meine Methodensignatur aufnehmen, damit sie aufgerufen werden konnte.Swift 2.2+ und Swift 3 Update
Verwenden Sie den neuen
#selector
Ausdruck, wodurch die Verwendung von Zeichenfolgenliteralen entfällt, wodurch die Verwendung weniger fehleranfällig wird. Als Referenz:wird
Siehe auch: Swift Evolution Proposal
Hinweis (Swift 4.0):
Bei Verwendung
#selector
müssten Sie die Funktion als markieren@objc
Beispiel:
@objc func something(_ sender: UIButton)
quelle
Swift 4.0
Sie erstellen den Selektor wie unten.
1. Fügen Sie das Ereignis einer Schaltfläche wie folgt hinzu:
und die Funktion wird wie folgt sein:
quelle
@objc
vorher zu setzen,func
was in Swift 4 erforderlich ist.Für zukünftige Leser stellte ich fest, dass ich ein Problem hatte und einen
unrecognised selector sent to instance
Fehler erhielt, der durch das Markieren des Zielsfunc
als privat verursacht wurde.Das
func
MUSS öffentlich sichtbar sein, um von einem Objekt mit einem Verweis auf einen Selektor aufgerufen zu werden.quelle
objc
bevor es Erklärung. Bsp.:@objc private func foo() { ...
Dann können Sie"foo"
als Selektor verwenden, wie Sieinternal
, dass kein Zugriffsmodifikator angegeben wird. Ich benutze oft dieses Muster://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
Nur für den Fall, dass jemand anderes das gleiche Problem mit NSTimer hat, bei dem keine der anderen Antworten das Problem behoben hat, ist es wirklich wichtig zu erwähnen, dass Sie eine Klasse verwenden, die weder direkt noch tief in der Hierarchie von NSObject erbt ( zB manuell erstellte schnelle Dateien), keine der anderen Antworten funktioniert, selbst wenn Folgendes angegeben ist:
Ohne etwas anderes zu ändern, als nur die Klasse von NSObject erben zu lassen, wurde der Fehler "Nicht erkannter Selektor" nicht mehr angezeigt und meine Logik funktionierte wie erwartet.
quelle
Wenn Sie einen Parameter vom NSTimer an die Funktion übergeben möchten, ist hier Ihre Lösung:
Fügen Sie den Doppelpunkt in den Auswahltext ein (Tester :), und Ihre Parameter gehen in userInfo.
Ihre Funktion sollte NSTimer als Parameter verwenden. Extrahieren Sie dann einfach userInfo, um den übergebenen Parameter abzurufen.
quelle
scheduledTimerWith...
fügt ihn nicht zu einem Runloop hinzu, während er automatisch zum aktuellen Runloop hinzugefügt wird - daher gibt es hier überhaupt kein seltsames Verhalten;)Selektoren sind eine interne Darstellung eines Methodennamens in Objective-C. In Objective-C würde "@selector (methodName)" eine Quellcodemethode in einen Datentyp von SEL konvertieren. Da Sie die @ selector-Syntax in Swift nicht verwenden können (Rickster ist dort aktiv), müssen Sie den Methodennamen manuell direkt als String-Objekt angeben oder ein String-Objekt an den Selector-Typ übergeben. Hier ist ein Beispiel:
oder
quelle
Swift 4.1
Mit Beispiel einer Tap-Geste
Weitere Informationen zu: Auswahlausdruck finden Sie im Apple-Dokument
quelle
quelle
// Kontrollmethode aktualisieren
quelle
Da Swift 3.0 veröffentlicht wird, ist es noch etwas subtiler, eine targetAction für angemessen zu erklären
quelle
Beim Benutzen
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
Methoden Ihre Methode (passend zum Selektor) sollte als markiert seinFür Swift 2.2 müssen Sie '#selector ()' anstelle von Zeichenfolge und Selektorname schreiben, damit die Möglichkeit von Rechtschreibfehlern und Abstürzen aufgrund dessen nicht mehr besteht. Unten ist ein Beispiel
quelle
Sie erstellen den Selektor wie unten.
1.
2.
Beachten Sie, dass die @ selector-Syntax nicht mehr vorhanden ist und durch einen einfachen String ersetzt wird, der die aufzurufende Methode benennt. Es gibt einen Bereich, in dem wir uns alle einig sein können, dass die Ausführlichkeit im Weg steht. Wenn wir deklarieren, dass es eine Zielmethode namens flatButtonPressed gibt, schreiben wir natürlich eine:
Stellen Sie den Timer ein:
Um vollständig zu sein, hier ist die flatButtonPressed
quelle
Ich fand viele dieser Antworten hilfreich, aber es war nicht klar, wie man das mit etwas macht, das kein Knopf ist. Ich habe einem UILabel schnell einen Gestenerkenner hinzugefügt und mich schwer getan. Nachdem ich alles oben gelesen habe, hat Folgendes für mich funktioniert:
Wo der "Selektor" deklariert wurde als:
Beachten Sie, dass es öffentlich ist und dass ich nicht die Selector () -Syntax verwende, aber es ist auch möglich, dies zu tun.
quelle
Wenn Sie #selector verwenden, wird Ihr Code beim Kompilieren überprüft, um sicherzustellen, dass die Methode, die Sie aufrufen möchten, tatsächlich vorhanden ist. Noch besser ist, wenn die Methode nicht vorhanden ist, wird ein Kompilierungsfehler angezeigt: Xcode weigert sich, Ihre App zu erstellen, und verbannt so, dass eine weitere mögliche Fehlerquelle vergessen wird.
quelle
Es kann hilfreich sein zu notieren, wo Sie das Steuerelement einrichten, das die Aktion auslöst.
Ich habe beispielsweise festgestellt, dass ich beim Einrichten eines UIBarButtonItem die Schaltfläche in viewDidLoad erstellen musste, da sonst eine nicht erkannte Selektorausnahme angezeigt wird.
quelle
Ändern Sie als einfache Zeichenfolgenbenennung in der Methode, die die Selektorsyntax aufruft
Geben Sie danach func test () ein.
quelle
selector
ist ein Wort aus derObjective-C
Welt und Sie können es von verwenden,Swift
um die Möglichkeit zu haben, von dortObjective-C
aus aufzurufen.Swift
Es ermöglicht Ihnen, zur Laufzeit Code auszuführenVor
Swift 2.2
der Syntax steht:Da ein Funktionsname
Selector
als String-Parameter ("foo") übergeben wird, ist es nicht möglich, einen Namen in der Kompilierungszeit zu überprüfen . Als Ergebnis können Sie einen Laufzeitfehler erhalten:Nach
Swift 2.2+
der Syntax lautet:Die automatische Vervollständigung von Xcode hilft Ihnen, eine richtige Methode aufzurufen
quelle
Für Swift 3
// Beispielcode zum Erstellen eines Timers
quelle
Auswahl in Swift 4:
quelle
Für schnelle 3
Funktionsdeklaration In derselben Klasse:
quelle
self
im Selektor vorhanden sein. Dies sollte ausreichen:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)