web-dev-qa-db-fra.com

L'argument de '#selector' ne fait pas référence à une méthode, une propriété ou un initialiseur '@objc'

J'ai sous-classé dans Swift 3 une sous-classe UIButton qui est écrite en Objective-C.

Lorsque j'essaie d'ajouter une cible, il échoue avec un code d'erreur:

class ActionButton: JTImageButton {

    func action() {

    }

    func configure()) {
        // ...
        self.addTarget(self, action: #selector(self.action()), for: .touchUpInside)
        // error: 
        // Argument of '#selector' does not refer to an '@objc' method, property, or initializer

    }
}
31
MJQZ1347

Tout ce que vous avez à faire est de marquer la fonction comme @objc et la référence self ou la parenthèse n'est pas nécessaire

class ActionButton: JTImageButton {

    @objc func btnAction() {

    }

    func configure() {
        // ...
        self.addTarget(self, action: #selector(btnAction), for: .touchUpInside)
        // error: 
        // Argument of '#selector' does not refer to an '@objc' method, property, or initializer

    }
}

Vous pouvez même le faire private si vous voulez

28
cjrieck

Le problème est que dans #selector(self.action()), self.action() est un appel de méthode. Vous ne voulez pas appeler la méthode; vous voulez name la méthode. Dites plutôt #selector(action): perdez les parenthèses, sans que le self ne soit pas nécessaire.

38
matt

Ajouter @objc mot-clé à l'avant la méthode qui est parfaite, mais j'ai toujours cette erreur. Enfin, j'ai trouvé la solution comme suit enter image description here

Il y a une paire de parenthèses superflues derrière la méthode, comme illustré ci-dessus. Ce que je devrais faire est que le supprimer et cela a bien fonctionné.

4
Victor John

Ajouté à partir de commentaires sur une autre réponse: func action () n'est pas simplement un mauvais choix pour un nom de fonction et une action, il ne parvient pas à se construire. (Vous pouvez toutefois l'utiliser comme paramètre de fonction d'entrée, ce que je fais par clarté lorsque je passe l'objectif/action à un init () qui définit ces paramètres.) Je remplace ceci par MyAction () pour plus de clarté.


Essaye ça:

self.addTarget(self, action: #selector(MyAction), for: .touchUpInside)

Cela dit, une meilleure conception consiste à déplacer la fonction MyAction () vers la superview du bouton, car cela rend les choses plus conformes à la conception de base de MVC:

Superview:

let myButton = ActionButton()
// include other button setup here
myButton.addTarget(self, action: #selector(MyAction), for: .touchUpInside

func action(_ sender: ActionButton) {
    // code against button tap here
}

Une autre solution consiste à conserver la méthode "action ()" dans le contrôleur de vue mais à déplacer niquement le "addTarget" dans le bouton:

self.addTarget(superview?, action(superview?.MyAction), for: .touchUpInside)

Pourquoi est-ce que je vous demande d'envisager de déplacer la méthode "MyAction ()" vers superview? Double:

  • Il contrôle non seulement le bouton, mais également toutes les autres sous-vues de sa vue, qui interagissent généralement les unes avec les autres via le contrôleur de vue.
  • Cela rend le bouton beaucoup plus réutilisable dans d'autres scénarios.
2
dfd

Au lieu de dire self.action(), utilisez ActionButton.action().

1
Bawpotter

Si cela ne vous dérange pas d'ajouter une fonction supplémentaire, vous pouvez l'imbriquer.

self.addTarget(self, action: myAction, for: UIControlledEvent)

myAction(){
    @obj.methodYouWantToCall(//parameters//)
}
0
Eugene Temlock