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/ astest 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 Selectortipo per lavorare con questi. (Swift lo utilizza automaticamente al posto del SELtipo 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 Selectorda un tipo di funzione Swift usando l' #selectorespressione.
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' #selectorespressione 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-selectorcontrollo del compilatore verifica solo l'esistenza del selettore denominato. Il riferimento alla funzione Swift che passi per #selectorverificare 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 #selectorall'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 ascast 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 #selectornon 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 Selectorda 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 privatesimboli non sono esposti al runtime: il tuo metodo deve avere almeno internalvisibilità.
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 KeyPathin 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, Selectorconforme 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()chiamerebbeteste passerebbe il suo valore di ritornoselectorall'argomento.