Swift selbst verwendet keine Selektoren - mehrere Designmuster, die in Objective-C Selektoren verwenden, funktionieren in Swift anders. (Verwenden Sie zum Beispiel optionale Verkettung bei Protokolltypen oder is
/as
Tests anstelle von respondsToSelector:
und verwenden Sie überall Closures, wo Sie können, anstelle von performSelector:
für bessere Typ-/Speichersicherheit.)
Aber es gibt immer noch eine Reihe wichtiger auf ObjC basierter APIs, die Selektoren verwenden, einschließlich Timer und dem Target/Action-Muster. Swift bietet den Typ Selector
für die Arbeit mit diesen an. (Swift verwendet automatisch dies anstelle von ObjCs SEL
Typ.)
In Swift 2.2 (Xcode 7.3) und später (einschließlich Swift 3 / Xcode 8 und Swift 4 / Xcode 9):
Sie können einen Selector
aus einem Swift-Funktionstyp mithilfe des #selector
Ausdrucks 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)
Der tolle an diesem Ansatz? Eine Funktionsreferenz wird vom Swift-Compiler überprüft, sodass Sie den #selector
Ausdruck nur mit Klassen/Methodenpaaren verwenden können, die tatsächlich existieren und für die Verwendung als Selektoren berechtigt sind (siehe "Selektor-Verfügbarkeit" unten). Sie können auch Ihre Funktionsreferenz nur so spezifisch machen, wie Sie benötigen, gemäß den Regeln für Funktionsnamen in Swift 2.2+.
(Dies ist tatsächlich eine Verbesserung gegenüber ObjCs @selector()
Direktive, da der Compiler das Überprüfen auf nicht deklarierte Selektoren nur daraufhin überprüft, ob der benannte Selektor existiert. Die Swift-Funktionsreferenz, die Sie an #selector
übergeben, prüft das Vorhandensein, die Zugehörigkeit zu einer Klasse und die Typensignatur.)
Es gibt ein paar zusätzliche Einschränkungen für die Funktionsreferenzen, die Sie an den #selector
Ausdruck übergeben:
- Mehrere Funktionen mit demselben Grundnamen können anhand ihrer Parameterbeschriftungen mit der oben genannten Syntax für Funktionsreferenzen unterschieden werden (z.B.
insertSubview(_:at:)
vs. insertSubview(_:aboveSubview:)
). Aber wenn eine Funktion keine Parameter hat, ist der einzige Weg, sie zu unterscheiden, die Verwendung eines as
Casts mit der Typsignatur der Funktion (z.B. foo as () -> ()
vs. foo(_:)
).
- Es gibt eine spezielle Syntax für Getter/Setter-Paare von Eigenschaften in Swift 3.0+. Zum Beispiel, bei einer
var foo: Int
, können Sie #selector(getter: MyClass.foo)
oder #selector(setter: MyClass.foo)
verwenden.
Allgemeine Anmerkungen:
Fälle, in denen #selector
nicht funktioniert, und Benennung: Manchmal haben Sie keinen Funktionsverweis, um einen Selektor zu erstellen (zum Beispiel bei Methoden, die dynamisch im ObjC-Laufzeitmodus registriert sind). In diesem Fall können Sie einen Selector
aus einer Zeichenkette erstellen: z.B. Selector("dynamicMethod:")
- obwohl Sie dabei die Gültigkeitsprüfung des Compilers verlieren. Wenn Sie das tun, müssen Sie die ObjC-Benennungsregeln befolgen, einschließlich Doppelpunkte (:
) für jeden Parameter.
Selektor-Verfügbarkeit: Die von dem Selektor referenzierte Methode muss dem ObjC-Laufzeitmodus zugänglich sein. In Swift 4 muss jede Methode, die an ObjC übergeben wird, ihre Deklaration mit dem Attribut @objc
versehen. (In früheren Versionen haben Sie in einigen Fällen dieses Attribut kostenlos erhalten, aber jetzt müssen Sie es explizit deklarieren.)
Vergessen Sie nicht, dass private
Symbole auch nicht dem Laufzeitmodus verfügbar sind - Ihre Methode muss mindestens eine Sichtbarkeit von internal
haben.
Schlüsselpfade: Diese sind mit, aber nicht genau dasselbe wie Selektoren. Es gibt auch eine spezielle Syntax dafür in Swift 3: z.B. chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Sehen Sie SE-0062 für Details. Und noch mehr KeyPath
-Kram in Swift 4, also stellen Sie sicher, dass Sie die richtige KeyPath-basierte API verwenden, anstatt Selektoren, wenn es angemessen ist.
Weitere Informationen zu Selektoren finden Sie unter Interaktion mit ObjC-APIs in Verwenden von Swift mit Cocoa und Objective-C.
Hinweis: Vor Swift 2.2 entsprach Selector
dem StringLiteralConvertible
, daher finden Sie möglicherweise alten Code, in dem nackte Zeichenfolgen an APIs übergeben werden, die Selektoren akzeptieren. Sie möchten in Xcode "In die aktuelle Swift-Syntax konvertieren" ausführen, um sicherzustellen, dass diese #selector
verwenden.