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 von respondsToSelector:
und verwenden Sie Verschlüsse, wo immer Sie können, anstatt performSelector:
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 des SEL
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.
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
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:
- Mehrere Funktionen mit demselben Basisnamen können anhand ihrer Parameterbezeichnungen unter Verwendung der oben genannten Syntax für Funktionsreferenzen (z . B.
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
) unterschieden werden. Wenn eine Funktion jedoch keine Parameter hat, besteht die einzige Möglichkeit, sie zu unterscheiden, darin, eine as
Umwandlung mit der Typensignatur der Funktion (z . B. foo as () -> ()
vs foo(_:)
) zu verwenden.
- In Swift 3.0+ gibt es eine spezielle Syntax für Property Getter / Setter-Paare. Wenn Sie beispielsweise a angeben
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 eine Selector
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 mindestens internal
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 mehr KeyPath
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
konform StringLiteralConvertible
, 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
.
selector: test()
würdetest
den Rückgabewert aufrufen und an dasselector
Argument übergeben.