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 SelectorTyp für die Arbeit mit diesen. (Swift verwendet dies automatisch anstelle des SELTyps von ObjC .)
In Swift 2.2 (Xcode 7.3) und höher (einschließlich Swift 3 / Xcode 8 und Swift 4 / Xcode 9):
SelectorMit dem #selectorAusdruck 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 #selectorAusdruck 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 #selectorExistenz, 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 #selectorAusdruck ü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 asUmwandlung 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 #selectordies 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 Selectoraus 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 @objcAttribut 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 privateSymbole auch nicht der Laufzeit ausgesetzt sind - Ihre Methode muss mindestens internalsichtbar 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 KeyPathDinge 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 Selectorkonform 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ürdetestden Rückgabewert aufrufen und an dasselectorArgument übergeben.