Swift stesso non utilizza i selettori: diversi modelli di design che in Objective-C utilizzano i selettori funzionano in modo diverso in Swift. (Ad esempio, utilizzare il concatenamento facoltativo su tipi di protocollo o is
/ as
test anziché respondsToSelector:
e utilizzare chiusure ovunque possibile anziché performSelector:
per una migliore sicurezza di tipo / memoria.)
Esistono tuttavia alcune importanti API basate su ObjC che utilizzano selettori, inclusi i timer e il modello di destinazione / azione. Swift fornisce il Selector
tipo per lavorare con questi. (Swift lo utilizza automaticamente al posto del SEL
tipo di ObjC .)
In Swift 2.2 (Xcode 7.3) e versioni successive (inclusi Swift 3 / Xcode 8 e Swift 4 / Xcode 9):
Puoi costruire un Selector
da un tipo di funzione Swift usando l' #selector
espressione.
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)
La cosa grandiosa di questo approccio? Il compilatore Swift verifica il riferimento di una funzione, pertanto è possibile utilizzare l' #selector
espressione solo con coppie classe / metodo effettivamente esistenti e idonee all'uso come selettori (vedere "Disponibilità del selettore" di seguito). Sei anche libero di rendere il riferimento alla tua funzione solo specifico di cui hai bisogno, secondo le regole di Swift 2.2+ per la denominazione del tipo di funzione .
(Questo è in realtà un miglioramento rispetto alla @selector()
direttiva di ObjC , perché il -Wundeclared-selector
controllo del compilatore verifica solo l'esistenza del selettore denominato. Il riferimento alla funzione Swift che passi per #selector
verificare l'esistenza, l'appartenenza a una classe e la firma del tipo.)
Ci sono un paio di avvertenze extra per i riferimenti di funzione che passi #selector
all'espressione:
- Più funzioni con lo stesso nome di base possono essere differenziate dalle loro etichette dei parametri utilizzando la sintassi di cui sopra per i riferimenti di funzione (ad es.
insertSubview(_:at:)
Vs insertSubview(_:aboveSubview:)
). Ma se una funzione non ha parametri, l'unico modo per chiarire l'ambiguità è usare un as
cast con la firma del tipo di funzione (ad es. foo as () -> ()
Vs foo(_:)
).
- Esiste una sintassi speciale per le coppie getter / setter di proprietà in Swift 3.0+. Ad esempio, dato un
var foo: Int
, puoi usare #selector(getter: MyClass.foo)
o #selector(setter: MyClass.foo)
.
Note generali:
Casi in cui #selector
non funziona e denominazione: a volte non si dispone di un riferimento di funzione con cui creare un selettore (ad esempio, con metodi registrati dinamicamente nel runtime di ObjC). In tal caso, puoi costruire un Selector
da una stringa: ad esempio Selector("dynamicMethod:")
, anche se perdi il controllo di validità del compilatore. Quando lo fai, devi seguire le regole di denominazione di ObjC, inclusi i due punti ( :
) per ciascun parametro.
Disponibilità del selettore: il metodo a cui fa riferimento il selettore deve essere esposto al runtime ObjC. In Swift 4, ogni metodo esposto a ObjC deve avere la sua dichiarazione preceduta dall'attributo @objc
. (Nelle versioni precedenti hai ottenuto l'attributo gratuitamente in alcuni casi, ma ora devi dichiararlo esplicitamente.)
Ricorda che anche i private
simboli non sono esposti al runtime: il tuo metodo deve avere almeno internal
visibilità.
Percorsi chiave: sono correlati ma non uguali ai selettori. C'è una sintassi speciale anche per questi in Swift 3: ad es chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Vedere SE-0062 per i dettagli. E ancora più contenuti KeyPath
in Swift 4 , quindi assicurati di utilizzare l'API basata su KeyPath corretta anziché i selettori, se appropriato.
Puoi leggere ulteriori informazioni sui selettori in Interazione con le API di Objective-C in Uso di Swift con Cocoa e Objective-C .
Nota: prima di Swift 2.2, Selector
conforme StringLiteralConvertible
, quindi potresti trovare il vecchio codice in cui le stringhe nude vengono passate alle API che accettano selettori. Ti consigliamo di eseguire "Converti in sintassi Swift corrente" in Xcode per ottenere quelli che utilizzano #selector
.
selector: test()
chiamerebbetest
e passerebbe il suo valore di ritornoselector
all'argomento.