2016-05-01 13 views
24

Ho un progetto Swift in cui voglio collegare un metodo all'evento di tocco di UIButton. Ho il seguente codice:Swift vuole che l'argomento #selector sia esposto a Objective-C

class MyClass { 
    let myButton = UIButton(frame: CGRectMake(50, 50, 100, 50)) 
    init() { 
    myButton.addTarget(self, #selector(self.didTap(_:)), forControlEvents: .TouchUpInside) 
    } 

    func didTap(sender: UIButton) { 
    print("Tapped") 
    } 
} 

XCode mette in evidenza la mia linea addTarget e dice:

Argument of '#selector' refers to a method that is not exposed to Objective-C 

Se posso aggiungere il prefisso @objc alla mia func didTap come suggerisce allora tutto funziona bene.

Ho qualcosa abilitato nelle impostazioni di compilazione che causa questo strano comportamento?

PS. Ho questo comportamento in 7.3.1. Ma se provo questo in 7.2.1 non accetta la sintassi #selector(method(_:)) e Selector("method:") funziona correttamente.

risposta

58

I selettori sono una funzionalità di Objective-C e possono essere utilizzati solo con i metodi esposti al runtime dinamico Obj-C. Non puoi avere un selettore per un metodo puro Swift.

Se la classe eredita da NSObject, i suoi metodi pubblici vengono automaticamente esposti a Obj-C. Poiché la classe non eredita da NSObject, è necessario utilizzare l'attributo @objc per indicare che si desidera che questo metodo sia esposto a Obj-C in modo che possa essere richiamato con un selettore Obj-C.

#selector() è la nuova sintassi in Swift 2.2. Permette al compilatore di verificare che il selettore che stai cercando di utilizzare esista effettivamente. La vecchia sintassi è deprecata e verrà rimossa in Swift 3.0.

+1

risposta ancora nitida e completa breve. Esattamente al punto. – MadNik

11

Se aggiungo il prefisso @objc al mio func didTap come suggerisce, allora tutto funziona correttamente.

Ho qualcosa abilitato nelle impostazioni di compilazione che causa questo strano comportamento?

No. Quello che stai vedendo è normale. I selettori sono una funzione Objective-C, quindi utilizza un selettore per inviare un messaggio all'istanza della classe. L'unico modo in cui Objective-C può inviare quel messaggio è se può vedere la tua classe o il metodo stesso. MyClass non è esso stesso derivato da NSObject, quindi Objective-C non può vederlo. Quindi, se non vuoi derivarlo da NSObject, devi almeno esporre il metodo a Objective-C contrassegnandolo con @objc.

e Selector ("Metodo:") funziona bene

Nelle versioni precedenti di Swift, il compilatore non aiuterebbe in questa situazione, in modo che il codice sarebbe la compilazione. Ma si sarebbe schiantato quando il messaggio è arrivato e Objective-C non è riuscito a trovare il metodo. L'intero punto della sintassi #selector è quello di aiutarti a evitare questo crash. E questo è proprio quello che ha fatto!

-2

si deve sottoclasse dalla NSObject